NC229892. 牛牛玩 generals
描述
输入描述
第一行三个正整数,。
第二行 个整数 ,表示第头牛家的位置。
然后 行,每行先输入一个整数 :
1. 若 ,再四个整数 ,表示一次占领事件。()2. 若 ,再输入一个数 。含义如上。对于 的数据,,。
输出描述
对于每一个询问,输出一行一个数表示答案。最后输出若干行,每行一个数,从小到大输出家没有被别人占领的牛的编号。
示例1
输入:
2 10 3 2 8 1 1 3 6 0 1 2 5 7 1 1 1 4 8 0
输出:
0 3 3 1
说明:
我们用Ⅰ表示牛1,用Ⅱ表示牛2。
上图为每一个操作结束以后的兵力分布。
第一次操作,牛Ⅰ扫荡3~6,这些位置是空地,故牛Ⅰ需要增援0。
第二次操作,牛Ⅱ扫荡5~7,这些位置中牛Ⅰ的有2*0兵力,故牛Ⅱ需要增援2*0+3*1=3,同时这三个位置都成为牛Ⅱ的1兵力。
第三次操作,牛Ⅰ扫荡4~8,这些位置中牛Ⅱ的有3*1+1*0兵力,故牛Ⅰ需要增援3+5*0=3,同时这五个位置都成为牛Ⅰ的0兵力,牛Ⅱ被牛Ⅰ吃掉。
最后只有牛Ⅰ活了下来 。
C++ 解法, 执行用时: 193ms, 内存消耗: 9048K, 提交时间: 2021-12-11 12:35:13
#include<bits/stdc++.h> using namespace std; int mk[100010]; struct tup{ int l,r,w,p; bool operator<(tup x)const{ return l<x.l; } }; set<tup>st; set<tup>::iterator it; int ans[100010],a[100010],fa[100010],sk[100010]; int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } int main(){ int n,m,t; scanf("%d%d%d",&n,&m,&t); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); mk[a[i]]=i;fa[i]=i; } for(int i=1;i<=m;++i)st.insert((tup){i,i,0,mk[i]}); while(t--){ int f; scanf("%d",&f); if(f==1){ int x,l,r,p,cnt=0; scanf("%d%d%d%d",&x,&l,&r,&p); it=st.upper_bound((tup){r,0,0,0}); int ans1=(r-l+1)*p,ans2=0,ans3=0; --it; while(1){ int l1=it->l,r1=it->r,w1=it->w,p1=it->p; if(r1<l)break; --it; st.erase((tup){l1,r1,w1,p1}); p1=find(p1); int l2=max(l1,l),r2=min(r1,r); if(p1==x)ans2+=w1*(r2-l2+1); else{ ans3+=w1*(r2-l2+1); ans[p1]-=w1*(r2-l2+1); if(l2<=a[p1]&&r2>=a[p1])sk[++cnt]=p1; } if(l1<l)st.insert((tup){l1,l-1,w1,p1}); if(r1>r)st.insert((tup){r+1,r1,w1,p1}); } st.insert((tup){l,r,p,x}); ans[x]+=ans1-ans2; printf("%d\n",ans1-ans2+ans3); for(int i=1;i<=cnt;++i)fa[sk[i]]=x,ans[x]+=ans[sk[i]]; } else{ int x; scanf("%d",&x); printf("%d\n",ans[x]); } } for(int i=1;i<=n;++i)if(fa[i]==i)printf("%d\n",i); }