题意:
这棵树上有 n 个节点,每个点的初始颜色为 ci c i 。
接下来进行 q 个操作:
1.修改树上某个点到另外一个点的简单路径上所有毒瘤的颜色。
2.对于给定的树上某个点集 S ,定义某个点集内的点的权值为:
Wi=∑j∈ST(i,j) W i = ∑ j ∈ S T ( i , j )
其中T(i,j)表示i到j的路径上的颜色的段数
每次指定树上 m 个节点作为点集,询问这 m 个节点的权值。
,,,1≤n,q≤100000,ci,y≤109,∑m≤200000,m≤n , , , 1 ≤ n , q ≤ 100000 , c i , y ≤ 10 9 , ∑ m ≤ 200000 , m ≤ n
Solution:
码农毒瘤题
1操作树剖+线段树可以维护,2操作建出虚树,虚树的边权值也可以通过树剖+线段树维护(其实树剖+线段树这方面和SDOI2011染色这道题一模一样)
求出虚树后可以通过点分治计算答案,具体的就是计算经过当前分治中心的路径对点集中所有点所产生的贡献,可以通过枚举并dfs子树来计算
锻炼代码能力的好题
写起来可休闲了
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int m,p[N],head[N],size,n,q,a[N],st[N],top,siz[N],dep[N],f[N][20],hs[N],dfn[N],tot,tf[N],dy[N];
int sz[N],rt,minn,ntot,xdfn[N],xu[N];
bool vis[N];
long long sum[N],totans,all;
struct tree{
int l,r,lv,rv,v,tag;
}tr[4*N];
struct edg{
int to,next,v;
}e[2*N];
void add(int x,int y)
{
size++;e[size].to=y;e[size].next=head[x];head[x]=size;
}
void dfs1(int x,int fa)
{
f[x][0]=fa;siz[x]=1;dep[x]=dep[fa]+1;
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].to;if (y==fa) continue;
dfs1(y,x);siz[x]+=siz[y];
if (siz[hs[x]]<siz[y]) hs[x]=y;
}
}
void dfs2(int x,int ff)
{
tf[x]=ff;dfn[x]=++tot;dy[tot]=x;
if (hs[x]) dfs2(hs[x],ff);
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].to;if (!dfn[y]) dfs2(y,y);
}
}
void update(int i)
{
tr[i].v=tr[i<<1].v+tr[i<<1|1].v;
if (tr[i<<1].rv==tr[i<<1|1].lv) tr[i].v--;
tr[i].lv=tr[i<<1].lv;tr[i].rv=tr[i<<1|1].rv;
// cout<<tr[i].l<<" "<<tr[i].r<<" "<<tr[i].v<<endl;
}
void build(int i,int l,int r)
{
tr[i].l=l,tr[i].r=r;
if (l==r) {
tr[i].v=1,tr[i].lv=tr[i].rv=a[dy[l]],tr[i].rv=a[dy[l]];return;}
int mid=l+r>>1;
build(i<<1,l,mid);build(i<<1|1,mid+1,r);
update(i);
}
void addtag(int i,int x)
{
tr[i].tag=x;
tr[i].v=1;tr[i].lv=tr[i].rv=x;
}
void pushdown(int i)
{
if (tr[i].tag) addtag(i<<1,tr[i].tag),addtag(i<<1|1,tr[i].tag),tr[i].tag=0;
}
void modify(int i,int l,int r,int x)
{
int L=tr[i].l,R=tr[i].r;
if (L>r||l>R) return;
if (l<=L&&R<=r) {addtag(i,x);return;}
pushdown(i);
modify(i<<1,l,r,x);modify(i<<1|1,l,r,x);
update(i);
}
int query(int i,int l,int r)
{
int L=tr[i].l,R=tr[i].r;
if (L>r||l>R) return 0;
if (l<=L&&R<=r) return tr[i].v;
pushdown(i);
int mid=L+R>>1;
if (r<=mid) return query(i<<1,l,r);
else if (l>mid) return query(i<<1|1,l,r);
else return query(i<<1,l,mid)+query(i<<1|1,mid+1,r)-(tr[i<<1].rv==tr[i<<1|1].lv);
}
int getp(int i,int pos)
{
int L=tr[i].l,R=tr[i].r;
if (L==R&&L==pos) return tr[i].lv;
pushdown(i);
int mid=L+R>>1;
if (pos<=mid) return getp(i<<1,pos);
else return getp(i<<1|1,pos);
}
bool cmp(int x,int y){
return dfn[x]<dfn[y];}
int LCA(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);//cout<<x<<" "<<y<<dep[x]<<dep[y]<<endl;
for (int i=19;i>=0;i--) if (dep[f[x][i]]>=dep[y]) x=f[x][i];
if (x==y) return x;
for (int i=19;i>=0;i--) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int getdis(int x,int y)
{
int ans=0;
while (tf[x]!=tf[y])
{
if (dep[tf[x]]<dep[tf[y]]) swap(x,y);
ans+=query(1,dfn[tf[x]],dfn[x]);
if (getp(1,dfn[tf[x]])==getp(1,dfn[f[tf[x]][0]])) ans--;
x=f[tf[x]][0];
}
if (dep[x]<dep[y]) swap(x,y);
ans+=query(1,dfn[y],dfn[x]);
return ans-1;
}
void addedg(int x,int y,int v)
{
// cout<<x<<" "<<y<<" "<<v<<endl;
size++;e[size].to=y;e[size].next=head[x];e[size].v=v;head[x]=size;
size++;e[size].to=x;e[size].next=head[y];e[size].v=v;head[y]=size;
}
void buildxtree()
{
top=0;
if (!xu[1]) st[++top]=1;
sort(p+1,p+1+m,cmp);
for (int i=1;i<=m;i++)
{
int lca=0;
while (top)
{
lca=LCA(st[top],p[i]);
if (top>1&&dep[lca]<dep[st[top-1]]) addedg(st[top],st[top-1],getdis(st[top],st[top-1])),top--;
else if (dep[lca]<dep[st[top]]) {addedg(lca,st[top],getdis(lca,st[top])),top--;break;}
else break;
}
if (st[top]!=lca) st[++top]=lca;
st[++top]=p[i];
}
while (top>1) addedg(st[top],st[top-1],getdis(st[top],st[top-1])),top--;
}
void dfsx1(int x,int fa)
{
xdfn[++ntot]=x;
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].to;if (y==fa) continue;
dfsx1(y,x);
}
}
void dfsx(int x,int fa)
{
sz[x]=1;
int nw=0;
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].to;if (y==fa||vis[y]) continue;
dfsx(y,x);sz[x]+=sz[y];
nw=max(nw,sz[y]);
}
nw=max(nw,ntot-sz[x]);
if (nw<minn) rt=x,minn=nw;
}
void findroot(int x)
{
minn=1e9;
dfsx(x,0);
}
void dfssiz(int x,int fa)
{
if (xu[x]) sz[x]=1;else sz[x]=0;
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].to;if (y==fa||vis[y]) continue;
dfssiz(y,x);sz[x]+=sz[y];
}
}
void dfsx2(int x,int fa,int dis)
{
if (xu[x]) totans+=dis;
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].to;if (y==fa||vis[y]) continue;
dfsx2(y,x,dis+e[i].v);
}
}
void dfsx3(int x,int fa,int dis)
{
if (xu[x]) sum[x]+=all+1ll*dis*ntot;
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].to;if (y==fa||vis[y]) continue;
dfsx3(y,x,dis+e[i].v);
}
}
void solve(int x)
{
//cout<<"NW: "<<x<<endl;
totans=0;dfssiz(x,0);ntot=sz[x];
dfsx2(x,0,1);if (xu[x]) sum[x]+=totans;
all=totans;//cout<<all<<endl;
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].to;if (vis[y]) continue;
totans=0;dfsx2(y,x,e[i].v+1);
ntot-=sz[y];all-=totans;//cout<<ntot<<" "<<all<<" "<<y<<endl;
dfsx3(y,x,e[i].v);//cout<<sum[10]<<endl;
ntot+=sz[y];all+=totans;
}
vis[x]=1;
for (int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if (!vis[y])
{
ntot=sz[y];
findroot(y);
solve(rt);
}
}
vis[x]=0;
}
bool cmp2(int x,int y) {
return xu[x]<xu[y];}
int main()
{
scanf("%d%d",&n,&q);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int x,y,i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs1(1,0);dfs2(1,1);build(1,1,n);
for (int i=1;i<=19;i++)for (int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1];
memset(head,0,sizeof(head));size=0;
for (int op,x,y,z,T=1;T<=q;T++)
{
scanf("%d",&op);
if (op==1)
{
scanf("%d%d%d",&x,&y,&z);
while (tf[x]!=tf[y])
{
if (dep[tf[x]]<dep[tf[y]]) swap(x,y);
modify(1,dfn[tf[x]],dfn[x],z);
x=f[tf[x]][0];
}
if (dep[x]<dep[y]) swap(x,y);
modify(1,dfn[y],dfn[x],z);
}
else
{
scanf("%d",&m);
for (int i=1;i<=m;i++) scanf("%d",&p[i]),xu[p[i]]=i;
buildxtree();dfsx1(1,0);int xsize=ntot;
findroot(1);solve(rt);
sort(p+1,p+1+m,cmp2);
for (int i=1;i<=m;i++) printf("%d ",sum[p[i]]),sum[p[i]]=0,xu[p[i]]=0;
for (int i=1;i<=xsize;i++)
head[xdfn[i]]=0;
size=0;
printf("\n");
}
}
}