1. 程式人生 > >BZOJ4999:This Problem Is Too Simple!(DFS序&樹上差分&線段樹動態開點:區間修改單點查詢)

BZOJ4999:This Problem Is Too Simple!(DFS序&樹上差分&線段樹動態開點:區間修改單點查詢)

Description

給您一顆樹,每個節點有個初始值。 現在支援以下兩種操作: 1. C i x(0<=x<2^31) 表示將i節點的值改為x。 2. Q i j x(0<=x<2^31) 表示詢問i節點到j節點的路徑上有多少個值為x的節點。

Input

第一行有兩個整數N,Q(1 ≤N≤ 100,000;1 ≤Q≤ 200,000),分別表示節點個數和操作個數。 下面一行N個整數,表示初始時每個節點的初始值。 接下來N-1行,每行兩個整數x,y,表示x節點與y節點之間有邊直接相連(描述一顆樹)。 接下來Q行,每行表示一個操作,操作的描述已經在題目描述中給出。

Output

對於每個Q輸出單獨一行表示所求的答案。

Sample Input

5 6
10 20 30 40 50
1 2
1 3
3 4
3 5
Q 2 3 40
C 1 40
Q 2 3 40
Q 4 5 30
C 3 10
Q 4 5 30

Sample Output

0
1
1
0

題意:給定一個數,頂點有顏色。 Q次操作,或修改單點顏色,或查詢路徑顏色為x的個數。

思路:由於是路徑,想到樹剖+線段樹,但是顏色個數無法合併,因此不行。  換個思路,用差分來求,然後把每個顏色弄個線段樹,然後這個顏色的線段樹單點代表的是這個點到根有多少這個顏色。    如果x點加了一個顏色為y的,那麼以y這棵樹,就再某個範圍加1,這個範圍是x的子樹的DFS序範圍;同理,減少則為-1 。

那麼查詢u到v路徑為x顏色的個數,就在x這棵樹上求sum[u]+sum[v]-sum[LCA]-sum[fa[LCA]];

自己寫了一遍,感覺動態開點好像也沒那麼難。 但是為什麼我的那麼慢啊。

(顏色需要離散化。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=100010;
struct in{
    int lson,rson,lazy;
    in(){lson=rson=lazy=0;}
}s[maxn
*80]; struct qqq{ char opt[3]; int u,v,x; }q[maxn<<1]; int dep[maxn],a[maxn],rt[maxn*6],fa[maxn][18],in[maxn],ou[maxn],Log[maxn]; int Laxt[maxn],Next[maxn<<1],To[maxn<<1],cnt,times,b[maxn*6],tot; void add(int u,int v){ Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } int LCA(int u,int v){ if(dep[u]<dep[v]) swap(u,v); for(int i=Log[dep[u]-dep[v]];i>=0;i--) if(dep[fa[u][i]]>=dep[v]) u=fa[u][i]; if(u==v) return u; for(int i=17;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; return fa[u][0]; } void dfs(int u,int f){ in[u]=++times;dep[u]=dep[f]+1; for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=f) dfs(To[i],u); ou[u]=times; fa[u][0]=f; } void pushdown(int Now){ if(s[Now].lazy!=0){ if(!s[Now].lson) s[Now].lson=++cnt; if(!s[Now].rson) s[Now].rson=++cnt; s[s[Now].lson].lazy+=s[Now].lazy; s[s[Now].rson].lazy+=s[Now].lazy; s[Now].lazy=0; } } void addnum(int &Now,int L,int R,int l,int r,int add){ if(!Now) Now=++cnt; if(l<=L&&r>=R){ s[Now].lazy+=add; return ; } int Mid=(L+R)>>1; pushdown(Now); if(l<=Mid) addnum(s[Now].lson,L,Mid,l,r,add); if(r>Mid) addnum(s[Now].rson,Mid+1,R,l,r,add); } int query(int Now,int L,int R,int pos){ if(!Now) return 0; if(L==R) return s[Now].lazy; int Mid=(L+R)>>1; pushdown(Now); if(pos<=Mid) return query(s[Now].lson,L,Mid,pos); return query(s[Now].rson,Mid+1,R,pos); } int main() { int N,Q,u,v,x; scanf("%d%d",&N,&Q); rep(i,2,N) Log[i]=Log[i>>1]+1; rep(i,1,N) scanf("%d",&a[i]),b[++tot]=a[i]; rep(i,1,N-1){ scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(1,0); cnt=0; rep(j,1,17) rep(i,1,N){ fa[i][j]=fa[fa[i][j-1]][j-1]; } rep(i,1,Q){ scanf("%s%d%d",q[i].opt,&q[i].u,&q[i].v); if(q[i].opt[0]=='Q') scanf("%d",&q[i].x),b[++tot]=q[i].x; else b[++tot]=q[i].v; } sort(b+1,b+tot+1); tot=unique(b+1,b+tot+1)-(b+1); rep(i,1,N) a[i]=lower_bound(b+1,b+tot+1,a[i])-b; rep(i,1,Q) { if(q[i].opt[0]=='Q') q[i].x=lower_bound(b+1,b+tot+1,q[i].x)-b; else q[i].v=lower_bound(b+1,b+tot+1,q[i].v)-b; } rep(i,1,N) addnum(rt[a[i]],0,N,in[i],ou[i],1); rep(i,1,Q){ u=q[i].u; v=q[i].v; if(q[i].opt[0]=='C'){ addnum(rt[a[u]],0,N,in[u],ou[u],-1); a[u]=v; addnum(rt[a[u]],0,N,in[u],ou[u],1); } else { x=q[i].x; int Lca=LCA(u,v); int res=query(rt[x],0,N,in[u]); res+=query(rt[x],0,N,in[v]); res-=query(rt[x],0,N,in[Lca]); res-=query(rt[x],0,N,in[fa[Lca][0]]); printf("%d\n",res); } } return 0; }