题目大意:给定一棵以1为根的有根树,每个节点有点权,提供两种操作:
1.以某个节点为根的子树所有节点权值+x
2.求一些链的并集的点权和,其中这些链都是由某个节点出发指向根
首先子树修改,链上查询,树链剖分的WT~
然后这些链上的每个点的点权都只能被加一次,肯定不能打标记,由于k<=5,我们考虑容斥原理
总权值=单链-两两之交+三链之交……
状压枚举即可 两条链的交集求法如下:
1.求两条链底的LCA
2.若LCA的深度小于其中一条链的链顶深度 交集为空 返回0
3.返回一条链 链底为LCA 链顶为两条链顶中深度较大的那个
此题mod2^31,直接自然溢出int,然后答案对2147483647取与即可 出题人真贴心-。-
时间复杂度O( m * log^2n * 2^k ) 看到这复杂度我都尿了0.0 不TLE真是太好了
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 200200 #define ls tree[p].lson #define rs tree[p].rson using namespace std; struct abcd{ int to,next; }table[M<<1]; struct Tree{ int lson,rson; int num,mark; }tree[M<<1];int tree_tot; int head[M],tot; int n,m,k; int fa[M],son[M],dpt[M],siz[M],top[M],pos[M],cnt; int digit[M]; pair<int,int>br[10]; void Build_Tree(int p,int x,int y) { int mid=x+y>>1; if(x==y) return ; ls=++tree_tot;rs=++tree_tot; Build_Tree(ls,x,mid); Build_Tree(rs,mid+1,y); } void Modify(int p,int x,int y,int l,int r,int v) { int mid=x+y>>1; if(x==l&&y==r) { tree[p].num+=(y-x+1)*v; tree[p].mark+=v; return ; } if(tree[p].mark) { tree[ls].mark+=tree[p].mark; tree[rs].mark+=tree[p].mark; tree[ls].num+=tree[p].mark*(mid-x+1); tree[rs].num+=tree[p].mark*(y-mid); tree[p].mark=0; } if(r<=mid) Modify(ls,x,mid,l,r,v); else if(l>mid) Modify(rs,mid+1,y,l,r,v); else Modify(ls,x,mid,l,mid,v) , Modify(rs,mid+1,y,mid+1,r,v); tree[p].num=tree[ls].num+tree[rs].num; } int Get_Ans(int p,int x,int y,int l,int r) { int mid=x+y>>1; if(x==l&&y==r) return tree[p].num; if(tree[p].mark) { tree[ls].mark+=tree[p].mark; tree[rs].mark+=tree[p].mark; tree[ls].num+=tree[p].mark*(mid-x+1); tree[rs].num+=tree[p].mark*(y-mid); tree[p].mark=0; } if(r<=mid) return Get_Ans(ls,x,mid,l,r); if(l>mid) return Get_Ans(rs,mid+1,y,l,r); return Get_Ans(ls,x,mid,l,mid) + Get_Ans(rs,mid+1,y,mid+1,r); } void DFS1(int x) { int i; siz[x]=1; dpt[x]=dpt[fa[x]]+1; for(i=head[x];i;i=table[i].next) { if(table[i].to==fa[x]) continue; fa[table[i].to]=x; DFS1(table[i].to); siz[x]+=siz[table[i].to]; if(siz[table[i].to]>siz[son[x]]) son[x]=table[i].to,swap(table[head[x]].to,table[i].to); } } void DFS2(int x) { int i; pos[x]=++cnt; top[x]=son[fa[x]]==x?top[fa[x]]:x; for(i=head[x];i;i=table[i].next) { if(table[i].to==fa[x]) continue; DFS2(table[i].to); } } void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } int Query(int x,int y) { int re=0,fx=top[x],fy=top[y]; while(fx!=fy) { if(dpt[fx]<dpt[fy]) swap(x,y),swap(fx,fy); re+=Get_Ans(0,1,n,pos[fx],pos[x]); fx=top[x=fa[fx]]; } if(dpt[x]<dpt[y]) swap(x,y); re+=Get_Ans(0,1,n,pos[y],pos[x]); return re; } int LCA(int x,int y) { int fx=top[x],fy=top[y]; while(fx!=fy) { if(dpt[fx]<dpt[fy]) fy=top[y=fa[fy]]; else fx=top[x=fa[fx]]; } return dpt[x]<dpt[y]?x:y; } pair<int,int> Cross(pair<int,int> x,pair<int,int> y) { int lca=LCA(x.first,y.first); if(dpt[lca]<dpt[x.second]||dpt[lca]<dpt[y.second]) return make_pair(-1,-1); return make_pair(lca,dpt[x.second]>dpt[y.second]?x.second:y.second); } int Calculate(int x) { int i; pair<int,int>re=make_pair(0,0); for(i=1;x;i++,x>>=1) if(x&1) { if(re.first==0) re=br[i]; else re=Cross(re,br[i]); if(re.first==-1) return 0; } return Query(re.first,re.second); } int Inclusion_Exclusion_Principle() { int i,re=0; for(i=1;i<1<<k;i++) re+=Calculate(i)*(digit[i]&1?1:-1); return re; } int main() { //freopen("3589.in","r",stdin); //freopen("3589.out","w",stdout); int i,j,x,y,p; cin>>n; for(i=1;i<n;i++) { scanf("%d%d",&x,&y); Add(x,y); Add(y,x); } DFS1(1); DFS2(1); Build_Tree(0,1,n); for(i=1;i<1<<5;i++) digit[i]=digit[i>>1]+(i&1); cin>>m; for(i=1;i<=m;i++) { scanf("%d",&p); if(!p) { scanf("%d%d",&x,&y); Modify(0,1,n,pos[x],pos[x]+siz[x]-1,y); } else { scanf("%d",&k); for(j=1;j<=k;j++) { scanf("%d%d",&x,&y); if(dpt[x]<dpt[y]) swap(x,y); br[j]=pair<int,int>(x,y); } printf("%d\n", Inclusion_Exclusion_Principle()&2147483647 ); } } }
原文地址:http://blog.csdn.net/popoqqq/article/details/40395193