[基本技巧]集合论
【问题描述】
集合论,是研究军训时紧急集合速度的理论,涉及到生物学,管理学,心理学等
多个领域.以上都是开学军训中的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 }