1. 程式人生 > >Wannafly挑戰賽16

Wannafly挑戰賽16

pri ont 結構 fir ins n) sta ise event

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

Wannafly挑戰賽16