题目大意:给定一棵以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 );
}
}
}