Wannafly挑战赛16

E(pbds)

题意:

  

  1<=m,n<=5e5

分析:

  首先指向关系形成了一个基环外向树森林

  实际上我们可以完全不用真正的去移动每个球,而只需要在计数的时候考虑考虑就行了

  对于树上的情况,我们假设在时间为now的时候在距离根为dis的点上放了个球,我们记录下now+dis

  对于询问树上的情况,即查找在时间为i的时候有多少个球会到达x点,那么我们只需要考虑以x为根的子树里(now+dis==i+d[x])的个数即可,很显然这可以用dfs序+数据结构来搞

  这个数据结构需要支持单点修改、询问区间内某一数字出现了多少次

  树状数组+主席树?

  我们换个角度,因为数字都不大,我们不妨对于每个数字都开一个set,查找就是在对应数字里的set里查找[l,r]中的数字有多少个,这个用pbds里的set就行了

  还有一个case,如果询问在环上咋办?

  我们可以记录每个球来到环上的时间,对于每个环直接用带模数组维护即可

 1 #include<bits/stdc++.h>
 2 #include<ext/pb_ds/assoc_container.hpp>
 3 #define mp make_pair
 4 using namespace std;
 5 using namespace __gnu_pbds;
 6 const int inf=1000000000;
 7 typedef tree<pair<int,int>,null_type,less<pair<int,int> >,rb_tree_tag,tree_order_statistics_node_update> rbtree;
 8 const int maxn=5e5;
 9 int f[maxn+5],fa[maxn+5],c[maxn+5],len[maxn+5];
10 int L[maxn+5],R[maxn+5],dep[maxn+5],root[maxn+5],id[maxn+5];
11 int n,m,ans,dfn,color;
12 vector<int> g[maxn+5];
13 rbtree rbt[2*maxn+5];
14 multiset<pair<int,int> > s;
15 map<int,int> a[maxn+5];
16 int find(int k)
17 {
18     if(f[k]==k) return k;
19     return f[k]=find(f[k]);
20 }
21 void addedge(int u,int v)
22 {
23     g[u].push_back(v);
24 }
25 void dfs(int k)
26 {
27     L[k]=++dfn;
28     for(auto u:g[k])
29     {
30         if(c[u]) continue;
31         dep[u]=dep[k]+1;
32         root[u]=root[k];
33         dfs(u);
34     }
35     R[k]=dfn;
36 }
37 int main()
38 {
39     scanf("%d",&n);
40     for(int i=1;i<=n;++i) f[i]=i;
41     for(int i=1;i<=n;++i) scanf("%d",&fa[i]),addedge(fa[i],i);
42     for(int i=1;i<=n;++i)
43     {
44         int u=find(i),v=find(fa[i]);
45         if(u!=v)
46         {
47             f[u]=v;
48             continue;
49         }
50         u=fa[i];
51         ++color;
52         int tmp=0;
53         while(true)
54         {
55             ++len[color];
56             c[u]=color;
57             id[u]=tmp++;
58             u=fa[u];
59             if(u==fa[i]) break;
60         }
61     }
62     for(int i=1;i<=n;++i)
63         if(c[i]) root[i]=i,dfs(i);
64     scanf("%d",&m);
65     for(int i=1;i<=m;++i)
66     {
67         int x;
68         scanf("%d",&x);
69         x^=ans;
70         if(c[x])
71         {
72             s.insert(mp(i,x));
73             while(!s.empty())
74             {
75                 pair<int,int> u=*s.begin();
76                 if(u.first>i) break;
77                 int color=c[u.second];
78                 ++a[color][(u.first-id[u.second]+len[color])%len[color]];
79                 s.erase(s.begin());
80             }
81             int color=c[x];
82             ans=a[color][(i-id[x]+len[color])%len[color]];
83             printf("%d\n",ans);
84         }
85         else
86         {
87             rbt[i+dep[x]].insert(mp(L[x],i));
88             ans=rbt[i+dep[x]].order_of_key(mp(R[x],inf))-rbt[i+dep[x]].order_of_key(mp(L[x],-inf));
89             printf("%d\n",ans);
90             s.insert(mp(i+dep[x],root[x]));
91         }
92     }
93     return 0;
94 }
View Code

F(数据结构)

题意:

  

  

分析:

  首先不考虑修改,对于一个给定的数组a,我们如何快速求出需要执行多少次操作才能把它全部变成0?

  我们可以发现以下的性质:

    1、有些位置对最终答案满贡献,其它位置对最终答案0贡献

    2、极大值对最终答案是满贡献的

    3、我们从初始的所有极大值开始每次隔1个数,直到遇到边界或者极小值,那么数到的数都会在过程中成为极大值

    4、若一个极小值对答案有贡献,那么它到两边的极大值的距离都为偶数

  于是我们就可以O(n)解决了

  但是现在有修改操作,我们来考虑如何在之前信息的基础上维护一些东西

  求答案的本质是找到那些极大值极小值,然后从极大值开始间隔1个数,我们可以用两个树状数组来维护奇数位/偶数位上的前缀和

  然后我们用一个set去存下所有的极大值、极小值

  对于一个修改(x,y)

  我们找到一个set里的极小区间[l,r],使得l和r的极大极小性质一定不会被破坏

  然后把这段区间对答案的贡献减掉

  然后修改a[x]->y

  再把这段区间对答案的贡献加上去

  时间复杂度O(nlogn)

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef set<int>::iterator iter;
  4 typedef long long ll;
  5 const int maxn=1e5;
  6 ll c[2][maxn+5];
  7 ll a[maxn+5];
  8 int n;
  9 ll ans=0;
 10 set<int> s;
 11 int lowbit(int x)
 12 {
 13     return x&(-x);
 14 }
 15 void add(ll *c,int k,ll x)
 16 {
 17     for(;k<=n/2+1;k+=lowbit(k)) c[k]+=x;
 18 }
 19 void add(int k,ll x)
 20 {
 21     if(k&1) add(c[1],(k+1)>>1,x);else add(c[0],(k+1)>>1,x);
 22 }
 23 ll query(ll *c,int k)
 24 {
 25     ll ans=0;
 26     for(;k;k-=lowbit(k)) ans+=c[k];
 27     return ans;
 28 }
 29 ll query(ll *c,int l,int r)
 30 {
 31     if(l>r) return 0;
 32     return query(c,r)-query(c,l-1);
 33 }
 34 int type(int id)
 35 {
 36     if(a[id-1]<a[id]&&a[id]>=a[id+1]) return 1;
 37     if(a[id-1]>=a[id]&&a[id]<a[id+1]) return -1;
 38     return 0;
 39 }
 40 ll cal(int l,int r)
 41 {
 42     if(r-l<3) return 0;
 43     if(a[l]<a[r])
 44     {
 45         int R=(r+1)/2-1;
 46         int L;
 47         if((l&1)==(r&1)) L=(l+1)/2+1;else L=(l+2)/2;
 48         return query(c[r&1],L,R);
 49     }
 50     else
 51     {
 52         int L=(l+1)/2+1;
 53         int R;
 54         if((l&1)==(r&1)) R=(r+1)/2-1;else R=r/2;
 55         return query(c[l&1],L,R);
 56     }
 57 }
 58 ll cal(iter l,iter r)
 59 {
 60     ll ans=0;
 61     for(iter i=l;i!=r;++i)
 62     {
 63         iter tmp=i;
 64         ++tmp;
 65         ans+=cal(*i,*tmp);
 66     }
 67     ++r;
 68     for(iter i=l;i!=r;++i)
 69             if(type(*i)==1) ans+=a[*i];
 70             else
 71                 if(type(*i)==-1)
 72                 {
 73                     iter tmp1=i,tmp2=i;
 74                     --tmp1,++tmp2;
 75                     if((*tmp2-*i)%2==0&&(*i-*tmp1)%2==0) ans+=a[*i];
 76                 }
 77             else
 78             {
 79                 iter tmp=i;
 80                 if(*i==1) ++tmp;else --tmp;
 81                 if((*tmp-*i)%2==0) ans+=a[*i];
 82             }
 83     return ans;
 84 }
 85 int main()
 86 {
 87     scanf("%d",&n);
 88     for(int i=1;i<=n;++i) scanf("%lld",&a[i]),add(i,a[i]);
 89     s.insert(1),s.insert(n);
 90     for(int i=2;i<n;++i)
 91         if(type(i)!=0) s.insert(i);
 92     iter tmp=s.end();
 93     ans=cal(s.begin(),--tmp);
 94     int q;
 95     scanf("%d",&q);
 96     for(int i=1;i<=q;++i)
 97     {
 98         int x;ll y;
 99         scanf("%d%lld",&x,&y);
100         int l=x-1,r=x+1;
101         if(r>n-1) r=n-1;
102         if(l<2) l=2;
103         iter L=s.lower_bound(l);
104         --L;
105         iter R=s.upper_bound(r);
106         ans-=cal(L,R);
107         int left=*L,right=*R;
108         add(x,y-a[x]);
109         a[x]=y;
110         if(type(x)!=0) s.insert(x);
111         else if(s.count(x)&&x>=2&&x<=n-1) s.erase(x);
112         if(x+1<n)
113             if(type(x+1)==0&&s.count(x+1)) s.erase(x+1);
114             else if(type(x+1)!=0) s.insert(x+1);
115         if(x-1>1)
116             if(type(x-1)==0&&s.count(x-1)) s.erase(x-1);
117             else if(type(x-1)!=0) s.insert(x-1);
118         L=s.lower_bound(left);
119         R=s.lower_bound(right);
120         ans+=cal(L,R);
121         printf("%lld\n",ans);
122     }
123     return 0;
124 }
View Code

猜你喜欢

转载自www.cnblogs.com/wmrv587/p/9119002.html