【BZOJ3211】花神游历各国 并查集+树状数组
【BZOJ3211】花神游历各国
Description
Input
Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
Sample Output
101
11
11
题解:网上好多题解说线段树,感觉树状数组+并查集就可以啊!
易知一个数只要开log(log(n))次平方就会变成1或0,所以我们用并查集维护没有变成1或0的点,修改的时候暴力修改那些没有变成1或0的点,用树状数组更新前缀和,查询的时候直接上树状数组,这样复杂度是O(nlogn*log(log(n)))的
注意!并查集的f[i]指向的是i下一个没有变成1或0的点,所以别忘了f[n+1]=n+1!!!(WA的教训)
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> using namespace std; const int maxn=100010; typedef long long ll; int n,m; int f[maxn]; ll v[maxn],s[maxn]; int find(int x) { return (f[x]==x)?x:(f[x]=find(f[x])); } void updata(int x,ll val) { for(int i=x;i<=n;i+=i&-i) s[i]+=val; } ll query(int x) { int i; ll ret=0; for(i=x;i;i-=i&-i) ret+=s[i]; return ret; } int main() { scanf("%d",&n); int i,j,a,b,c; for(i=1;i<=n;i++) scanf("%lld",&v[i]),updata(i,v[i]),f[i]=i; f[n+1]=n+1; scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d%d%d",&c,&a,&b); if(a>b) swap(a,b); if(c==1) { printf("%lld\n",query(b)-query(a-1)); continue; } for(j=find(a);j<=b;j=find(j+1)) { updata(j,-v[j]),v[j]=(ll)sqrt(1.0*v[j]),updata(j,v[j]); if(v[j]==1) f[j]=find(j+1); } } return 0; }
嘿嘿嘿我long long写错了你们看不见,略略略~
同上帝造题的7分钟2,但是说好的双倍经验呢?我那道题long long写错就拿不到分了~QAQ
| 欢迎来原网站坐坐! >原文链接<