hdu 3333 Turing Tree 线段树 + 离线

题目链接

题目给定一个序列,让后查询m个区间,输出区间内数的和,重复的不计算多次。
想了半天也没想出来怎么在线维护这样的线段树,那就考虑一下离线怎么做。如果把区间按右端点排序,那么每次查询 [ l , r ] 的时候,如果都能保证 [ 1 , r ] 内重复数字的下标都在最右边,那这样即可避免重复了,而且还能保证每次查询的准确性。也就是说每次询问,看一下 [ 1 , r ] 是否已经确定,如果还没确定的话就需要遍历到 r ,这样就保证了每次 [ 1 , r ] 区间内没有重复的数字,且下标都只保留最右边。
最好是用树状数组写,线段树在洛谷能被卡掉好几个点,当初想用在线做所以敲了个线段树,不想改了

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N=30010,M=100010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n;
int a[N],b[N];
LL ans[M];
struct query
{
    int l,r;
    bool operator < (const query &w) const
    {
        return r<w.r;
    }
    int id;
}q[M];
struct Node
{
    int l,r;
    LL sum;
}tr[N<<2];

void pushup(int u)
{
    tr[u].sum=tr[L].sum+tr[R].sum;
}

void build(int u,int l,int r)
{
    tr[u]={l,r,0};
    if(l==r)
    {
        tr[u].sum=0;
        return;
    }
    build(L,l,Mid),build(R,Mid+1,r);
    pushup(u);
}

LL query(int u,int l,int r)
{
    if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;
    LL ans=0;
    if(l<=Mid) ans+=query(L,l,r);
    if(r>Mid) ans+=query(R,l,r);
    pushup(u);
    return ans;
}

void modify(int u,int l,int r,LL c)
{
    if(tr[u].l>=l&&tr[u].r<=r)
    {
        tr[u].sum+=c;
        return;
    }
    if(l<=Mid) modify(L,l,r,c);
    else modify(R,l,r,c);
    pushup(u);
}

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    int t; cin>>t;
    while(t--)
    {
        int tot=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
        int m; scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].id=i;
        }
        sort(q+1,q+1+m);
        build(1,1,n);
        map<LL,int>mp; int t=1;
        for(int i=1;i<=m;i++)
        {
            int l=q[i].l,r=q[i].r;
            while(t<=r)
            {
                if(!mp.count(a[t]))
                    modify(1,t,t,a[t]);
                else
                {
                    modify(1,mp[a[t]],mp[a[t]],-a[t]);
                    modify(1,t,t,a[t]);
                }
                mp[a[t]]=t; t++;
            }
            ans[q[i].id]=query(1,l,r);
        }
        for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
    }



	return 0;
}
/*

*/



猜你喜欢

转载自blog.csdn.net/DaNIelLAk/article/details/107034388