标签:fine update last name iostream ret end 思路 lag
暑假刚学树状数组时就看了这个题,当时挺无头绪的。之后在昨天写了一道区间查询不同个数的模板题,转头发现这个题也是个模板......
思路:用树状数组维护一个长度为输入总数长度的数组,然后向树状数组输入每一个位置的值,从该位置开始向上更新,每个数组值++,如果这个值在之前最近的位置出现过,所对应的最近位置向上更新,每个数组值--。向下查询的时候返回从下标1位置到当前查询位置所有的不同个数,query(r)-query(l-1)所得到的就是整个区间之内所有不同的数的个数。现在剩下的就是要离线一下,把查询按r的顺序从小到大排一遍,边查询边更新树状数组。
树状数组难的还是想着怎么维护啊。
代码写的特别乱,但还是水过了
#include <set> #include <map> #include <cmath> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define ll long long #define inf 0x3f3f3f3f using namespace std; const int Maxn=1000010; int pos[Maxn],tree[Maxn],num[Maxn],n,ans[Maxn]; struct st { int l,r,flag,ans; }q[Maxn]; bool cmp(st a, st b) { return a.r<b.r; } void update(int x,int y,int k) { if(k==1) { for(;x<=n;x+=x & (-x)) tree[x]++; } if(k==2) { for(;x<=n;x+=x & (-x)) tree[x]--; for(;y<=n;y+=y & (-y)) tree[y]++; } } int query(int x) { int ans=0; for(;x>0;x-=x & (-x)) ans+=tree[x]; return ans; } int main() { int m; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&num[i]); scanf("%d",&m); int l,r; for(int i=1;i<=m;i++) {scanf("%d%d",&l,&r); q[i].l=l; q[i].r=r; q[i].flag=i;} sort(q+1,q+m+1,cmp); int last=1; for(int i=1;i<=m;i++) { int j; //cout<<i<<" "<<last<<" "<<q[i].r<<endl; for(j=last;j<=q[i].r;j++) { int temp=num[j]; if(!pos[temp]) update(j,pos[temp],1); if(pos[temp]) update(pos[temp],j,2); pos[temp]=j; } //for(int i=1;i<=n;i++) cout<<i<<" "<<tree[i]<<endl; last=j; //cout<<q[i].flag<<endl; //cout<<q[i].l<<" "<<q[i].r<<" "; if(q[i].r==q[i].l) ans[q[i].flag]=1; else ans[q[i].flag]=query(q[i].r)-query(q[i].l-1); //if(q[i].r==q[i].l) cout<<1<<endl; //else cout<<query(q[i].r)-query(q[i].l-1)<<endl; } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
标签:fine update last name iostream ret end 思路 lag
原文地址:https://www.cnblogs.com/benzikun/p/11629164.html