[基本技巧]集合论

【问题描述】
集合论,是研究军训时紧急集合速度的理论,涉及到生物学,管理学,心理学等
多个领域.以上都是开学军训中的liu_runda的瞎扯.
集合论是现代数学的基础.因此liu_runda以集合为背景出了一个题目.
liu_runda相信,这道优雅简洁的题目,能使选手们充分发挥自己的水平.
你只需要维护整数集合A,一开始的时候A是空集,接下来我们将依次执行m
次操作,每次操作后,你都要输出集合 A 中所有元素之和.如果 A 是空集,认为所有
元素之和是0.
操作分为 4种类型
union 操作:给出一个集合 B,然后A=A∪B
intersection 操作:给出一个集合B,然后A=A∩B
plus 操作:如果 A 不为空,A 集合中的每个元素 x 的数值都增加 1,否则什么都
不做
minus 操作:如果 A 不为空,A 集合中的每个元素 x 的数值都减少 1,否则什么
都不做

【输入格式】
输入文件 jihe.in
第一行一个整数 m,表示操作的次数.
接下来 m 行,每行描述一个操作.
每行的开始都是一个数字,1,2,3,4依次代表 union, intersection, plus, minus.
对于 plus 和minus 操作,这一行只包含数字 3或数字4.
对于 union 和 intersection 操作,数字 1 或 2 后面会给出集合 B.集合 B 与前面
的数字之间用空格隔开.集合B的描述方式是:首先给出一个数字Size表示集合B
的元素个数,接下来给出 Size个空格隔开的整数.保证这Size个整数互不相同.
【输出格式】
输出文件 jihe.out
m 行,第i 行一个整数,表示第i 次操作之后集合 A中所有元素之和

【数据规模和约定】
我们用 SUM 表示给出的集合的 Size 之和(也就是给出的集合的元素总个
数),MAX表示给出的集合中元素的绝对值的最大值
第 1个测试点:只有plus 操作和 minus 操作,m<=10^5
第2,3个测试点: m<=10^5
,SUM<=10^5
,MAX<=10^6
,没有plus操作和minus操作
第4个测试点: m<=10^5
,SUM<=3*10^6
,MAX<=10^6
,没有plus操作和minus操作
和intersection 操作.
第5,6,7,8个测试点:m<=10^5
,SUM<=3*10^6
,MAX<=10^6
,没有plus操作和minus
操作
第 9,10个测试点:m<=10^3
,SUM<=10^3
,MAX<=10^3
 
第 11,12,13,14,15 个测试点:m<=10^5
,SUM<=10^5
,MAX<=10^6
第11个测试点还满足:所有plus和minus操作出现在所有intersection和union
操作之后.
第 16,17,18,19,20个测试点:m<=10^5
,SUM<=3*10^6
,MAX<=10^6

题解

开一个桶   求并集直接加 求交集用时间戳删除之前A的  整体加减用懒标记 别忘了整体加减影响值域

我数据结构学傻了 当即写了一发权值线段树,调了半天还TLE。。

 1 #include<cstdio>
 2 using namespace std;
 3 const int C=1100000,N=2*1100000+15;
 4 
 5 
 6 char xch,xB[1<<15],*xS=xB,*xTT=xB;
 7 #define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++)
 8 inline int read()
 9 {
10 int x=0,f=1;char ch=getc();
11 while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getc();}
12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
13 return x*f;
14 }
15 struct point{int l,r,exi,cnt,lazy; long long sum,tot;}t[4*N];
16 void build(int i,int l,int r)
17  {t[i].l=l; t[i].r=r;
18   if(l==r) return;
19   int mid=t[i].l+t[i].r>>1;
20   build(2*i,l,mid); build(2*i+1,mid+1,r);
21  }
22 inline void pushup(int i)
23   {t[i].exi=t[2*i].exi+t[2*i+1].exi;
24    t[i].cnt=t[2*i].cnt+t[2*i+1].cnt;
25    t[i].sum=t[2*i].sum+t[2*i+1].sum;
26    t[i].tot=t[2*i].tot+t[2*i+1].tot;
27   }
28  inline void pass(int i)
29   {t[i].lazy++; t[i].tot-=t[i].sum; t[i].sum=t[i].tot; t[i].cnt-=t[i].exi; t[i].exi=t[i].cnt;
30   }
31  inline void pushdown(int i)
32    {while(t[i].lazy) {pass(2*i); pass(2*i+1); t[i].lazy--;} 
33     // aaaaaaaaaaaa while bushi if 
34    }
35 void add(int i,long long x,int op)
36  {if(t[i].l==t[i].r)  {x=x-C;
37                        if(op==1)
38                         {t[i].cnt=t[i].exi=1; t[i].sum=t[i].tot=x;
39                         }
40                         else if(op==2)
41                         {if(t[i].cnt==0) { t[i].cnt=t[i].exi=1; t[i].sum=t[i].tot=x;}
42                          else            { t[i].cnt=2; t[i].exi=1; t[i].sum=x; t[i].tot=x*t[i].cnt; }
43                         }
44                         return;
45                       }
46    int mid=t[i].l+t[i].r>>1; pushdown(i);
47    if(x<=mid) add(2*i,x,op);
48    else           add(2*i+1,x,op);
49    pushup(i);
50  }/*
51 void print(int i)
52  {if(t[i].exi) 
53     printf("%d %d %d %d %d %lld %lld %d\n",
54                       i,t[i].l,t[i].r,
55                       t[i].exi,t[i].cnt,
56                       t[i].sum,t[i].tot,
57                       t[i].lazy);
58   if(t[i].l==t[i].r) {
59                           return;}                      
60   //pushdown(i);
61   if(t[2*i].exi)     print(2*i);
62   if(t[2*i+1].exi) print(2*i+1);
63  }*/
64 int main()
65 {int m; m=read();  int op,siz,r,del=0;
66  build(1,1,C*2+3);
67  while(m--)
68   {op=read();
69    if(op==1)        { siz=read();
70                       while(siz--) {r=read(); r=r+C-del;    add(1,r,1);     }
71                     }
72    else if(op==2)
73                     { siz=read();
74                       while(siz--) {r=read();  r=r+C-del;   add(1,r,2);      }
75                       pass(1);
76                     }
77    else if(op==3) {del++;}
78    else if(op==4) {del--;}
79   //print(1); //printf("\n");
80    printf("%lld\n",t[1].sum+t[1].exi*del);
81   }
82 return 0;
83 }

线段树求交集 先加进线段树在整体减1 注意一个节点可能有多次lazy标记, 不要当成区间覆盖。。

 1 #include<cstdio>
 2 using namespace std;
 3 const int C=1100000,N=2*1100000+15;
 4 int T=1,t[N];
 5 char xch,xB[1<<15],*xS=xB,*xTT=xB;
 6 #define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++)
 7 inline int read()
 8 {
 9 int x=0,f=1;char ch=getc();
10 while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getc();}
11 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
12 return x*f;
13 }
14 int main()
15  {
16  freopen("jihe.in","r",stdin);
17  freopen("jihe.out","w",stdout);    
18  int m; m=read();  int op,siz,r,del=0;    long long ans=0,cnt=0;
19  while(m--)    
20   {op=read(); 
21    if(op==1)
22      {siz=read();
23       while(siz--) {r=read(); r=r+C-del;
24                     if(t[r]!=T) {cnt++; ans=ans+r-C; }
25                     
26                     t[r]=T; 
27                    }
28      }    
29    else if(op==2)
30      {siz=read(); T++; ans=cnt=0;
31       while(siz--) {r=read(); r=r+C-del;
32                     if(t[r]==T-1) {t[r]=T; cnt++; ans=ans+r-C; }
33                    }
34      }
35    else if(op==3) del++;
36    else if(op==4) del--;
37    printf("%lld\n",ans+cnt*del);         
38   }    
39 return 0;
40  }

 

posted @ 2019-11-13 16:34  YuXiaoze  阅读(577)  评论(0编辑  收藏  举报