https://codeforces.com/contest/911/problem/G
没想到线段树合并还能这么搞。。
对每个权值建一个线段树(动态开点),如果权值为k的线段树上第i位为1,那么表示a[i]=k;如果权值为k的线段树上第i位为0,表示a[i]≠k
改变权值的时候,就是把[l,r]分解成多个线段树上的区间;对于每个分解出的区间,分别在权值为x的线段树上和权值为y的线段树上找到对应的节点,设某个区间找到的节点为a,b,则把b子树合并到a上
注意!要特判x==y时跳过操作
最后枚举一遍所有权值得到答案
复杂度n*100+n*log
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 #define fi first 8 #define se second 9 #define mp make_pair 10 #define pb push_back 11 typedef long long ll; 12 typedef unsigned long long ull; 13 typedef pair<int,int> pii; 14 namespace S 15 { 16 #define N 4000000 17 int d[N],lc[N],rc[N]; 18 queue<int> q; 19 void init() 20 { 21 for(int i=1;i<N;i++) q.push(i); 22 } 23 int getnode() 24 { 25 int t=q.front();q.pop(); 26 lc[t]=rc[t]=d[t]=0; 27 return t; 28 } 29 void delnode(int x){q.push(x);} 30 void addx(int L,int x,int l,int r,int &num) 31 { 32 if(!num) num=getnode(); 33 if(l==r) {d[num]+=x;return;} 34 int mid=l+((r-l)>>1); 35 if(L<=mid) addx(L,x,l,mid,lc[num]); 36 else addx(L,x,mid+1,r,rc[num]); 37 } 38 int merge(int x,int y) 39 { 40 if(!x||!y) return x+y; 41 lc[x]=merge(lc[x],lc[y]); 42 rc[x]=merge(rc[x],rc[y]); 43 d[x]+=d[y]; 44 delnode(y); 45 return x; 46 } 47 void work(int L,int R,int l,int r,int &n1,int &n2) 48 { 49 if(!n1) n1=getnode(); 50 if(L<=l&&r<=R) {n1=merge(n1,n2);n2=0;return;} 51 int mid=l+((r-l)>>1); 52 if(L<=mid) work(L,R,l,mid,lc[n1],lc[n2]); 53 if(mid<R) work(L,R,mid+1,r,rc[n1],rc[n2]); 54 } 55 int ans[201000]; 56 void dfs(int l,int r,int k,int num) 57 { 58 if(l==r) 59 { 60 if(d[num]) ans[l]=k; 61 return; 62 } 63 int mid=l+((r-l)>>1); 64 dfs(l,mid,k,lc[num]);dfs(mid+1,r,k,rc[num]); 65 } 66 } 67 int rt[101]; 68 int n; 69 int main() 70 { 71 int t,i,l,r,x,y,q; 72 S::init(); 73 scanf("%d",&n); 74 for(i=1;i<=n;i++) 75 { 76 scanf("%d",&t); 77 S::addx(i,1,1,n,rt[t]); 78 } 79 scanf("%d",&q); 80 while(q--) 81 { 82 scanf("%d%d%d%d",&l,&r,&x,&y); 83 if(x==y) continue; 84 S::work(l,r,1,n,rt[y],rt[x]); 85 } 86 for(i=1;i<=100;i++) S::dfs(1,n,i,rt[i]); 87 for(i=1;i<=n;i++) printf("%d ",S::ans[i]); 88 return 0; 89 }
(分块也能做,不过我自己写的常数太糟...开了Ofast交了几十发后也只A了一次。。。)