题意:
给出一颗n个结点的树,每个结点上有一种糖果∈[1,m];
一个人经过这个结点品尝糖果j获得的愉悦度为w[time[j]]*val[j] (其中time[j]指j的品尝次数);
给出q次操作,操作有两种:
1:更改某结点的糖果种类;
2:查询某两个结点路径上的愉悦度总和;
题解:
250s的神题,orz各位神犇;
将树分块,每块n^2/3大小,分成n^1/3块;
用莫队算法统计路径上每种糖果的数量;
但是这里有了修改,不能用原来的方式排序了;
所以以左端点所在块为第一关键字,右端点所在块为第二关键字,时间序为第三关键字为所有询问排序;
注意是对询问排序,而修改仍按时间序存储;
然后一一处理询问,每次更改端点之前先把时间调至某次修改之后;
每次调整都是O(1)的,答案就是每个糖果的val乘上w的前缀和了;
这样时间复杂度最坏在O(n^5/3) (LCA的log似乎被忽视了);
我的代码可以跑进100s真是荣幸啊233
代码:
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
using namespace std;
typedef long long ll;
struct node
{
int l,r,tim,posl,posr,no;
}Q[N];
int to[N<<1],next[N<<1],head[N];
int st[N],belong[N],deep[N],fa[N][20];
int a[N],s[N];
int opx[N],opf[N],opt[N],last[N];
int cnt,tot,bk,top;
ll v[N],w[N],ans[N];
ll now;
bool vis[N];
bool cmp(node a,node b)
{
if(a.posl==b.posl)
{
if(a.posr==b.posr)
return a.tim<b.tim;
return a.posr<b.posr;
}
return a.posl<b.posl;
}
void add(int x,int y)
{
to[++cnt]=y;
next[cnt]=head[x];
head[x]=cnt;
}
void dfs(int x,int pre,int d)
{
deep[x]=d;
fa[x][0]=pre;
int i,y,b=top;
for(i=head[x];i;i=next[i])
{
if((y=to[i])!=pre)
{
dfs(y,x,d+1);
if(top-b>=bk)
{
tot++;
while(top>b)
belong[st[top--]]=tot;
}
}
}
st[++top]=x;
}
int Lca(int x,int y)
{
while(deep[x]!=deep[y])
{
if(deep[x]<deep[y])
swap(x,y);
int k=log2(deep[x]-deep[y]);
x=fa[x][k];
}
if(x==y) return x;
int k=log2(deep[x])+1;
while(k>=0)
{
if(fa[x][k]!=fa[y][k])
x=fa[x][k],y=fa[y][k];
k--;
}
return fa[x][0];
}
void update(int x,int op)
{
now-=w[s[x]]*v[x];
s[x]+=op;
now+=w[s[x]]*v[x];
}
void change(int t)
{
if(a[opx[t]]==opf[t])
{
a[opx[t]]=opt[t];
if(vis[opx[t]])
{
update(opf[t],-1);
update(opt[t],1);
}
}
else
{
a[opx[t]]=opf[t];
if(vis[opx[t]])
{
update(opt[t],-1);
update(opf[t],1);
}
}
}
void slove(int x1,int x2)
{
int g=Lca(x1,x2);
while(x1!=g)
{
update(a[x1],vis[x1]?-1:1);
vis[x1]=!vis[x1];
x1=fa[x1][0];
}
while(x2!=g)
{
update(a[x2],vis[x2]?-1:1);
vis[x2]=!vis[x2];
x2=fa[x2][0];
}
}
int main()
{
int n,m,q,i,j,k,l,r,x,y,len,op,temp,ti;
scanf("%d%d%d",&n,&m,&q);
bk=pow(n,2.0/3);
for(i=1;i<=m;i++)
scanf("%lld",v+i);
for(i=1;i<=n;i++)
scanf("%lld",w+i),w[i]=w[i-1]+w[i];
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
for(i=1;i<=n;i++)
scanf("%d",a+i),last[i]=a[i];
dfs(1,0,0);
while(top)
belong[st[top--]]=tot;
for(k=1;(1<<k)<=n;k++)
for(i=1;i<=n;i++)
fa[i][k]=fa[fa[i][k-1]][k-1];
for(i=1,temp=len=0;i<=q;i++)
{
scanf("%d%d%d",&op,&x,&y);
if(op)
{
temp++;
if(belong[x]>belong[y])
swap(x,y);
Q[temp].l=x,Q[temp].r=y;
Q[temp].posl=belong[x];
Q[temp].posr=belong[y];
Q[temp].tim=len,Q[temp].no=temp;
}
else
{
len++;
opx[len]=x,opf[len]=last[x],opt[len]=y;
last[x]=y;
}
}
q=temp;
sort(Q+1,Q+q+1,cmp);
l=1,r=1,now=0,ti=0;
for(i=1;i<=q;i++)
{
while(ti<Q[i].tim) change(++ti);
while(ti>Q[i].tim) change(ti--);
slove(l,Q[i].l);
slove(r,Q[i].r);
l=Q[i].l,r=Q[i].r;
x=Lca(l,r);
update(a[x],1);
ans[Q[i].no]=now;
update(a[x],-1);
}
for(i=1;i<=q;i++)
printf("%lld\n",ans[i]);
return 0;
}
原文地址:http://blog.csdn.net/ww140142/article/details/47373935