hdu 4288 线段树 暴力 **

题意:
维护一个有序数列{An},有三种操作:
1、添加一个元素。
2、删除一个元素。
3、求数列中下标%5 = 3的值的和。
解题思路:
看的各种题解,今天终于弄懂了。
由于线段树中不支持添加、删除操作,所以题解写的是用离线做法。
我们来看它是如何解决添加、删除的问题的。
首先将所有出现过的数记录下来,然后排序去重,最后根据去重结果建树,然后每个操作数都会对应线段树中的一个点。
遇到添加、删除操作的时候,只要把那个节点的值改变,然后将它对下标的影响处理好就可以。
那么如何处理这些操作对下标的影响呢?
现在我们考虑一个父区间,假设它的左右子区间已经更新完毕。
显然,左区间中下标%5的情况与父区间中%5的情况完全相同;
可是,右区间中却不一定相同,因为右区间中的下标是以 mid 当作 1 开始的。
那么,只要我们知道左区间中有效元素的个数 cnt,我们就能知道右区间中的下标 i 在父区间中对应的下标为 i+cnt。
所以,虽然我们最终要的只是总区间中下标%5 = 3的和。但是在更新时我们需要知道右区间%5的所有情况。
于是我们要在线段树的每个节点开一个 sum[5] 和一个 cnt,分别记录这个节点中下标%5的5种情况的和与有效元素的个数。
而查询时,直接访问总区间的 sum[3] 即可。
如此,题目便可解了。复杂度O(M logN logN)。

以前用的是线段树,这次用暴力来了一发

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<map>
 8 using namespace std;
 9 #define MOD 1000000007
10 const int INF=0x3f3f3f3f;
11 const double eps=1e-5;
12 typedef long long ll;
13 #define cl(a) memset(a,0,sizeof(a))
14 #define ts printf("*****
");
15 const int N=51005;
16 int n,m,tt;
17 int main()
18 {
19     int i,j,k,ca=1;
20     #ifndef ONLINE_JUDGE
21     freopen("1.in","r",stdin);
22     #endif
23     while(scanf("%d",&n)!=EOF)
24     {
25         int len=0;
26         vector<int> vc;
27         int x;
28         vector<int>::iterator it;
29         char s[10];
30         while(n--)
31         {
32             scanf("%s",s);
33             if(s[0]=='a')
34             {
35                 len++;
36                 scanf("%d",&x);
37                 it=lower_bound(vc.begin(),vc.end(),x);
38                 vc.insert(it,x);
39             }
40             else if(s[0]=='d')
41             {
42                 len--;
43                 scanf("%d",&x);
44                 it=lower_bound(vc.begin(),vc.end(),x);
45                 vc.erase(it);
46             }
47             else
48             {
49                 ll sum=0;
50                 for(i=2;i<len;i+=5)
51                 {
52                     sum+=vc[i];
53                 }
54                 printf("%I64d
",sum);
55             }
56         }
57     }
58 }
View Code
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #define lson l,mid,rt<<1
 8 #define rson mid+1,r,rt<<1|1
 9 #define root 1,n,1
10 #define mid ((l+r)>>1)
11 #define ll long long
12 #define cl(a) memset(a,0,sizeof(a))
13 #define ts printf("*****
");
14 using namespace std;
15 const int MAXN=100005;
16 ll sum[MAXN<<2][5];
17 vector<int> num;
18 int cnt[MAXN<<2],val[MAXN];
19 char cz[MAXN],s[1024];
20 int n,m,t;
21 int getid(int v)
22 {
23     return lower_bound(num.begin(),num.end(),v)-num.begin()+1;
24 }
25 void pushup(int rt)
26 {
27     cnt[rt]=cnt[rt<<1]+cnt[rt<<1|1];
28     for(int i=0;i<5;i++) sum[rt][i]=sum[rt<<1][i];
29     for(int i=0;i<5;i++) sum[rt][(i+cnt[rt<<1])%5]+=sum[rt<<1|1][i];    //这两个不能放一起,找了好长时间
30 }
31 int tot=0;
32 void update(int pos,int v,int l,int r,int rt)
33 {
34     if(l==r)
35     {
36         sum[rt][1]=num[pos-1]*v;
37         cnt[rt]=v;
38         return;
39     }
40     if(pos<=mid)    update(pos,v,lson);
41     else    update(pos,v,rson);
42     pushup(rt);
43 }
44 int main()
45 {
46     int i,j,k,q;
47     #ifndef ONLINE_JUDGE
48     freopen("1.in","r",stdin);
49     #endif
50     while(~scanf("%d",&n))
51     {
52         num.clear();
53         for(i=1;i<=n;i++)
54         {
55             scanf("%s",s);
56             cz[i]=s[0];
57             if(s[0]!='s')
58             {
59                 scanf("%d",val+i);
60                 num.push_back(val[i]);
61             }
62         }
63         cl(sum),cl(cnt);
64         sort(num.begin(),num.end());
65         num.erase(unique(num.begin(),num.end()),num.end());
66         int sumn=num.size();
67         for(int i=1;i<=n;i++)
68         {
69             if(cz[i] == 'a') update(getid(val[i]),1,1,sumn,1);
70             else if(cz[i] == 'd') update(getid(val[i]),0,1,sumn,1);
71             else printf("%I64d
",sum[1][3]);
72         }
73     }
74     return 0;
75 }
原文地址:https://www.cnblogs.com/cnblogs321114287/p/4356512.html