2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 8465 Solved: 3170
[Submit][Status][Discuss]
Description
給定一棵有n個節點的無根樹和m個操作,操作有2類:
1、將節點a到節點b路徑上所有點都染成顏色c;
2、詢問節點a到節點b路徑上的顏色段數量(連續相同顏色被認爲是同一段),如“112221”由3段組成:“11”、“222”和“1”。
請你寫一個程序依次完成這m個操作。
Input
第一行包含2個整數n和m,分別表示節點數和操作數;
第二行包含n個正整數表示n個節點的初始顏色
下面 行每行包含兩個整數x和y,表示x和y之間有一條無向邊。
下面 行每行描述一個操作:
“C a b c”表示這是一個染色操作,把節點a到節點b路徑上所有點(包括a和b)都染成顏色c;
“Q a b”表示這是一個詢問操作,詢問節點a到節點b(包括a和b)路徑上的顏色段數量。
Output
對於每個詢問操作,輸出一行答案。
Sample Input
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
1
2
HINT
數N<=10^5,操作數M<=10^5,所有的顏色C爲整數且在[0, 10^9]之間。
Source
巨難受
終於調A了
調了好久QAQ
還是師兄給力
好久沒寫4000K的代碼了
線段樹的部分其實不難,合併的時候如果左區間的右端點顏色和右區間的左端點顏色相同
那麼ans--(ans=左邊的ans+右邊的ans)
難點在樹鏈剖分部分
我們發現合併的順序和方向對答案是有影響的
所以我們要把u邊的ans和v邊的ans的分開存
然後討論左右問題
發現我們在線段樹裏面得到的區間都是左邊id小的,右邊id大的
而id是dfs序,所以id小的深度一定較小
v這邊也是一樣的
所以我們每次都把新得到的區間放在之前的答案的左邊
而當他們在一條重鏈上時
我們需要將新查詢出的答案的左右端點分別跟ans1,ans2比較
重點還是要理解我們每次查詢得到的區間,都是左端點高,右端點低
剩下的就可以推出來了(感謝師兄QAQ)
#include<cstdio>
#include<cstring>
const int N=1e5+7;
struct node
{
int l,r;
int sum,ll,rr;
int set;
void clear()
{
sum=0,ll=0,rr=0;
}
}e[N*4];
struct edgt
{
int to,next;
}s[N*2];
int cnt,first[N];
int size[N],id[N],dep[N],fa[N];
inline void insert(int u,int v)
{
s[++cnt]=(edgt){v,first[u]};first[u]=cnt;
s[++cnt]=(edgt){u,first[v]};first[v]=cnt;
}
#define lson ro<<1
#define rson ro<<1|1
inline void pushup(node &ro,node l,node r)
{
ro.ll=l.ll;
ro.rr=r.rr;
ro.sum=l.sum+r.sum;
if(l.rr==r.ll) ro.sum--;
}
void build(int ro,int l,int r)
{
e[ro].l=l;e[ro].r=r;
if(l==r) return;
int mid=(l+r)>>1;
build(lson,l,mid);build(rson,mid+1,r);
}
#define lazy e[ro].set
inline void pushdown(int ro)
{
if(lazy)
{
e[lson].ll=e[lson].rr=lazy;
e[rson].ll=e[rson].rr=lazy;
e[lson].sum=e[rson].sum=1;
e[lson].set=lazy;
e[rson].set=lazy;
lazy=0;
}
}
node query(int ro,int l,int r)
{
if(l<=e[ro].l&&e[ro].r<=r) return e[ro];
pushdown(ro);
int mid=(e[ro].l+e[ro].r)>>1;
if(r<=mid) return query(lson,l,r);
else if(l>mid) return query(rson,l,r);
else
{
node a=query(lson,l,mid);node b=query(rson,mid+1,r);
node ans;ans.clear();
pushup(ans,a,b);
return ans;
}
}
void modify(int ro,int l,int r,int k)
{
if(l<=e[ro].l&&e[ro].r<=r)
{
e[ro].ll=e[ro].rr=k;lazy=k;e[ro].sum=1;
return;
}
pushdown(ro);
int mid=(e[ro].l+e[ro].r)>>1;
if(l<=mid) modify(lson,l,r,k);
if(r>mid) modify(rson,l,r,k);
pushup(e[ro],e[lson],e[rson]);
}
void dfs1(int x)
{
size[x]=1;
for(int k=first[x];k;k=s[k].next)
{
if(s[k].to==fa[x]) continue;
fa[s[k].to]=x;
dep[s[k].to]=dep[x]+1;
dfs1(s[k].to);
size[x]+=size[s[k].to];
}
}
int sz;int top[N];
void dfs2(int x,int chain)
{
int i=0;
id[x]=++sz;top[x]=chain;
for(int k=first[x];k;k=s[k].next)
if(dep[s[k].to]>dep[x]&&size[s[k].to]>size[i]) i=s[k].to;
if(!i) return;
dfs2(i,chain);
for(int k=first[x];k;k=s[k].next)
if(dep[s[k].to]>dep[x]&&s[k].to!=i) dfs2(s[k].to,s[k].to);
}
inline void swap(int &a,int &b)
{
int tmp=a;a=b;b=tmp;
}
int qsum(int u,int v)
{
node ans1,ans2,a;ans1.clear(),ans2.clear();//lca左邊和右邊的答案
bool tag=1;bool flag1=0,flag2=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v),tag^=1;;
a=query(1,id[top[u]],id[u]);
if(tag)
{
if(flag1)pushup(ans1,a,ans1);
else ans1.sum=a.sum,ans1.ll=a.ll,ans1.rr=a.rr,flag1=1;
}
else
{
if(flag2)pushup(ans2,a,ans2);
else ans2.sum=a.sum,ans2.ll=a.ll,ans2.rr=a.rr,flag2=1;
}
u=fa[top[u]];
}
if(id[u]>id[v]) swap(u,v),tag^=1;
a=query(1,id[u],id[v]);
int ans=a.sum;
if(tag){
if(flag1){
ans+=ans1.sum;
if(ans1.ll==a.ll) ans--;
}
if(flag2){
ans+=ans2.sum;
if(ans2.ll==a.rr) ans--;
}
}
else{
if(flag1){
ans+=ans1.sum;
if(ans1.ll==a.rr) ans--;
}
if(flag2){
ans+=ans2.sum;
if(ans2.ll==a.ll) ans--;
}
}
return ans;
}
void qset(int u,int v,int k)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
modify(1,id[top[u]],id[u],k);
u=fa[top[u]];
}
if(id[u]>id[v]) swap(u,v);
modify(1,id[u],id[v],k);
}
int vi[N];
void change(int ro,int x)
{
if(e[ro].l==e[ro].r)
{
e[ro].sum=1;e[ro].ll=e[ro].rr=vi[x];return;
}
int mid=(e[ro].l+e[ro].r)>>1;
if(id[x]<=mid) change(lson,x);
else change(rson,x);
pushup(e[ro],e[lson],e[rson]);
}
int main()
{
int n,m,u,v;
scanf("%d %d",&n,&m);
build(1,1,n);
for(int i=1;i<=n;i++) scanf("%d",&vi[i]);
for(int i=1;i<n;i++) scanf("%d %d",&u,&v),insert(u,v);
dfs1(1);dfs2(1,1);
for(int i=1;i<=n;i++) change(1,i);
char a[2];
int q;
for(int i=1;i<=m;i++)
{
scanf("%s %d %d",a,&u,&v);
if(a[0]=='C') scanf("%d",&q),qset(u,v,q);
else printf("%d\n",qsum(u,v));
}
return 0;
}