Mass Change Queries Codeforces - 911G

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了一次。。。)

posted @ 2018-07-31 13:48  hehe_54321  阅读(352)  评论(0编辑  收藏  举报
AmazingCounters.com