题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4836
题目大意:
中文题面,不多解释了。
解题思路:
这道题如果去除了第3个操作的话其实就是裸的树上dfs序+线段树的操作,但是因为有了操作3,题目就变得复杂了许多。
这里的话刚开始我是每次换了根都重新dfs序一遍,结果,错的跟tm智障一样,理所当然t了。
这里其实我们可以拿一个变量root记录根的位置,我们发现如果换了根之后,root 不处于x的子树的话,那么我们查询x的子树仍然是正常查询。画个图的话应该很容易明白。但是如果我们的根变成了x的子树内的结点应该怎么办呢,其实结合图我们仍然可以发现 新的x的值应该是当前树上所有节点的值减去一个结点y子树内所有结点的值,那么这个y结点是什么呢,其实就是我们x到root的那条边上x的儿子结点,反正结合图很容易就明白了,最后还有一种特殊情况就是x和root重合,那就完全不用说了= = ,以上这些判断我们都通过lca来求就行了
Ac代码,
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
typedef long long ll;
const int N=1e5+5;
const int INF=1e9+7;
const int P=18;
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int n,m,cnt,root,a[N];
int dep[N],par[N][21]; //lca
char s[100];
struct node
{
int l,r;
}qu[N]; //dfs序
struct Node
{
int l,r,mid;
int sum;
}t[N*4];
vector<int> v[N];
void pushup(int rt) //简单的线段树操作
{
t[rt].sum=t[lson].sum+t[rson].sum;
}
void build(int l,int r,int rt)
{
int m=(l+r)>>1;
t[rt].l=l,t[rt].r=r;
t[rt].mid=m;
if(l==r)
{
t[rt].sum=0;
return ;
}
build(l,m,lson);
build(m+1,r,rson);
pushup(rt);
}
void update(int pos,int x,int rt)
{
if(t[rt].l==t[rt].r)
{
t[rt].sum=x;
return ;
}
if(pos<=t[rt].mid)
update(pos,x,lson);
if(pos>t[rt].mid)
update(pos,x,rson);
pushup(rt);
}
int query(int l,int r,int rt)
{
//printf("%d %d\n",t[rt].l,t[rt].r);
if(l<=t[rt].l&&t[rt].r<=r)
return t[rt].sum;
int ans=0;
if(l<=t[rt].mid)
ans+=query(l,r,lson);
if(r>t[rt].mid)
ans+=query(l,r,rson);
return ans;
}
void init() //求lca
{
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i<=n;i++)
par[i][j]=par[par[i][j-1]][j-1];
}
void dfs(int k)
{
qu[k].l=++cnt; //求得dfs序
for(int i=0;i<(int)v[k].size();i++)
{
int u=v[k][i];
if(!dep[u])
{
dep[u]=dep[k]+1,par[u][0]=k;
dfs(u);
}
}
qu[k].r=cnt;
}
int lca(int vv,int uu)
{
if(dep[vv]<dep[uu])
swap(uu,vv);
int d=dep[vv]-dep[uu];
for(int i=0;(d>>i)!=0;i++)
if((d>>i)&1) vv=par[vv][i];
if(vv==uu)
return vv;
for(int i=20;i>=0;i--)
{
if(par[vv][i]!=par[uu][i])
{
vv=par[vv][i];
uu=par[uu][i];
}
}
return par[vv][0];
}
int find(int x) //当root位于查询结点子树内 找到y结点
{
for(int i=0;i<v[x].size();i++)
{
int u=v[x][i];
if(dep[u]<dep[x]) continue;
int k=lca(root,u);
if(k==u)
return u;
}
}
int main()
{
int QAQ,kase=0;
scanf("%d",&QAQ);
while(QAQ--)
{
cnt=0;
memset(dep,0,sizeof dep);
memset(par,0,sizeof par);
scanf("%d",&n);
for(int i=0;i<=n;i++)
v[i].clear();
for(int i=1;i<n;i++)
{
int p,q;
scanf("%d%d",&p,&q);
v[p].push_back(q);
v[q].push_back(p);
}
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
dep[1]=1;
dfs(1),root=1;
init();
build(1,n,1);
for(int i=1;i<=n;i++)
update(qu[i].l,a[i],1);
printf("Case #%d:\n",++kase);
while(m--)
{
int p,x;
scanf(" %s",s);
if(s[0]=='Q')
{
scanf("%d",&p);
int la=lca(p,root); //对应上文提到的各种情况
if(p==root)
printf("%d\n",t[1].sum);
else if(p!=la)
printf("%d\n",query(qu[p].l,qu[p].r,1));
else if(p==la)
{
int k=find(p);
printf("%d\n",t[1].sum-query(qu[k].l,qu[k].r,1));
}
}
if(s[0]=='C')
{
scanf("%d%d",&p,&x);
a[p]=x;
update(qu[p].l,x,1);
}
if(s[0]=='R')
{ //直接改变根结点即可
scanf("%d",&x);
root=x;
}
}
}
//system("pause");
}