题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3333
题目大意:有n个数,m次询问,每次询问$[l,r]$中不同数的和
Sample Input
2 3 1 1 4 2 1 2 2 3 5 1 1 2 1 3 3 1 5 2 4 3 5
Sample Output
1 5 6 3 6
emmmm,看到这题。。。很明显我们可以对询问按照$r$小优先排序,然后我们将每个数丢到线段树的时候看看这个数是否出现过,如果出现过了,那么很明显,坐标越大的越优(如果$l$能够覆盖小坐标,那么一定能够覆盖大坐标),所以我们直接删除掉上一个位置的值,然后在新的位置更新该值。至于查看,我们可以用unordered_map来记录一下。
还有就是cin,cout即使关了同步。。。也好慢的说QAQ。。。cout中用来endl跑了2500+ms,用' '代替endl跑了1500+ms,用scanf,printf跑了500+ms
以下是AC代码:
#include <cstring> #include <algorithm> #include <cstdio> #include <iostream> #include <unordered_map> using namespace std; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define lc rt<<1 #define rc rt<<1|1 typedef long long ll; const int mac=3e4+10; const int maxn=1e5+10; struct node { int l,r,id; bool operator<(const node&a)const{ return r<a.r; } }qs[maxn]; ll tree[mac<<2],ans[maxn]; int a[mac]; void update(int l,int r,int rt,int pos,int val) { if (l==r) {tree[rt]+=val; return;} int mid=(l+r)>>1; if (mid>=pos) update(lson,pos,val); else {update(rson,pos,val);} tree[rt]=tree[lc]+tree[rc]; } ll query(int l,int r,int rt,int L,int R) { ll ans=0; if (l>=L && r<=R) return tree[rt]; int mid=(l+r)>>1; if (mid>=L) ans+=query(lson,L,R); if (mid<R) ans+=query(rson,L,R); return ans; } int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int t; cin>>t; while (t--){ int n,m; cin>>n; for (int i=1; i<=n; i++) cin>>a[i]; cin>>m; for (int i=1; i<=m; i++){ int l,r; cin>>l>>r; qs[i]=node{l,r,i}; } sort(qs+1,qs+1+m); memset(tree,0,sizeof tree); unordered_map<int,int>q; int st=1; for (int i=1; i<=m; i++){ while (qs[i].r>=st){ if (q[a[st]]) update(1,n,1,q[a[st]],-a[st]); update(1,n,1,st,a[st]); q[a[st]]=st; st++; } ans[qs[i].id]=query(1,n,1,qs[i].l,qs[i].r); } for (int i=1; i<=m; i++) cout<<ans[i]<<' '; } return 0; }