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;View Code6 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 }
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