【校内互侧】Sunshine’s city (lct+线段树)
Sunshine’s city(city.cpp)
【问题描述】在很久很久之前Sunshine建立了一个n个城市的王国 (城市从0开始编号),其中0 号城市是Sunshine 居住的地方,也就是首都。追求完美的 Sunshine国王把整个王国的道路设计成了一棵树的形状, 两个城市之间有且只有一条道路能到达。
Sunshine 王国是一个文化多元的国家。初始时,每个城市都有一中单独的文化。当居民在相邻的城市间移动时,如果这两个城市不是同一种文化,那么需要付出一个单位的代价。
体恤国民的 Sunshine 想要减少居民的支出。具体说来,他会每次将首都到一个城市u 路径上的所有城市都发展成一种新的文化。因为这个原因,来往于城市间的代价会经常改变, 于是Sunshine 找你来帮忙。 给定一个城市 u, 定义 f(u)为以u 为根的子树中所有节点到根节点的代价的和。
【输入格式】
第一行有一个整数 n 表示城市的数目。 接下来 n-1 行每行两个整数Ai,Bi 表示一条连接这两点的道路。
接下来一行一个整数 m, 表示接下来有 m 组操作, 每组操作包含一个字符 t和一个整数 u。 如果 t='O',表示一个新的帮会占据了从首都到 u 路径上的城市。 如果 t='q',表示询问 f(u)。
【输出格式】
对于每组测试数据中的 t='q'类型的询问,输出一行一个整数表示 f(u)。
【样例输入】
13
0 1
0 2
1 11
1 10
1 9
9 12
2 5
5 8
2 4
2 3
4 6
4 7
7
q 0
O 4
q 6
q 2
O 9
q 9
q 2
【样例输出】
26
1
6
1
13
【数据规模及约定】
对于 30%的数据n,m<=1000
对于 60%的数据n,m<=50000
另外存在 20%的数据,树是一条链。
对于100%的数据n,m<=200000
——————————————————————————————————
【题解】【lct+线段树】
【可以发现,这道题中的修改操作很像lct中的access操作,so,必然lct啊,但是这个题的lct题比较好写,只有link和access操作;然后因为要求区间和,所以要用线段树来维护,区间的话用dfs序搞一下就行了(求dfs序的时候要用非递归,我因为用了递归,RERERE……)】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int f[400010],ch[400010][2],col[400010],cnt;
int a[400010],nxt[400010],p[200010],tot;
int cur[400010],L[400010],R[400010],pre[400010];
int que[400010],top;
ll sum[1600010],delta[1600010];
int n,m;
inline void add(int x,int y)
{
tot++; a[tot]=y; nxt[tot]=p[x]; p[x]=tot;
tot++; a[tot]=x; nxt[tot]=p[y]; p[y]=tot;
}
inline void pushdown(int now,int l,int r,int mid)
{
if(delta[now])
{
sum[(now<<1)]+=(mid-l+1)*delta[now]; sum[(now<<1)|1]+=(r-mid)*delta[now];
delta[(now<<1)]+=delta[now]; delta[(now<<1)|1]+=delta[now];
delta[now]=0;
}
}
inline void updata(int now)
{
sum[now]=sum[(now<<1)]+sum[(now<<1)|1];
}
void change(int now,int l,int r,int al,int ar,int v)
{
if(al<=l&&r<=ar)
{
sum[now]+=(ll)(r-l+1)*(ll)v;
delta[now]+=(ll)v;
return;
}
int mid=(l+r)>>1;
pushdown(now,l,r,mid);
if(al<=mid) change((now<<1),l,mid,al,ar,v);
if(ar>mid) change((now<<1)|1,mid+1,r,al,ar,v);
updata(now);
}
ll ask(int now,int l,int r,int al,int ar)
{
if(al<=l&&r<=ar) return sum[now];
int mid=(l+r)>>1;
pushdown(now,l,r,mid);
ll ans=0;
if(al<=mid) ans+=ask((now<<1),l,mid,al,ar);
if(ar>mid) ans+=ask((now<<1)|1,mid+1,r,al,ar);
return ans;
}
void dfs()
{
top=0;
for(int i=1;i<=n;++i) cur[i]=p[i];
que[++top]=1; pre[1]=0;
while(top)
{
int x=que[top];
if(a[cur[x]]==pre[x]) cur[x]=nxt[cur[x]];
if(!cur[x])
{
--top;
R[x]=cnt;
continue;
}
int v=a[cur[x]];
que[++top]=v; pre[v]=x; L[v]=++cnt;
cur[x]=nxt[cur[x]];
}
}
inline int isroot(int x)
{
return (ch[f[x]][0]!=x&&ch[f[x]][1]!=x);
}
inline int get(int x)
{
return ch[f[x]][1]==x;
}
inline void rotate(int x)
{
int fa,olf,which;
fa=f[x]; olf=f[fa]; which=get(x);
if(!isroot(fa)) ch[olf][ch[olf][1]==fa]=x;
ch[fa][which]=ch[x][which^1]; f[ch[x][which^1]]=fa;
f[fa]=x; ch[x][which^1]=fa; f[x]=olf;
}
inline void splay(int x)
{
while(!isroot(x))
{
int y=f[x];
if(!isroot(y))
rotate(get(x)==get(y)?y:x);
rotate(x);
}
}
inline void link(int x,int y)
{
f[x]=y;
}
inline int find(int x)
{
while(ch[x][0]) x=ch[x][0];
return x;
}
inline void access(int x,int num)
{
int tmp=0;
while(x)
{
col[x]=num;
splay(x);
int t=find(ch[x][1]);
if(t)
change(1,1,n,L[t],R[t],1);
ch[x][1]=tmp;
int t1=find(tmp);
if(t1)
change(1,1,n,L[t1],R[t1],-1);
tmp=x; x=f[x];
}
}
int main()
{
freopen("city.in","r",stdin);
freopen("city.out","w",stdout);
int i; tot=0;
memset(p,0,sizeof(p));
memset(nxt,0,sizeof(nxt));
scanf("%d",&n);
for(i=1;i<n;++i)
{
int x,y;
scanf("%d%d",&x,&y);
x++; y++;
add(x,y); link(y,x);
}
dfs();
for(i=2;i<=n;++i) change(1,1,n,L[i],R[i],1);
scanf("%d\n",&m);
int size=n;
for(i=1;i<=n;++i) col[i]=i;
for(i=1;i<=m;++i)
{
int x; char opt;
scanf("%c%d",&opt,&x);
getchar();
x++;
if(opt=='q') printf("%lld\n",ask(1,1,n,L[x],R[x]));
else access(x,++size);
}
return 0;
}
既然无能更改,又何必枉自寻烦忧