C107 整体二分+树状数组(区修+点查)P3527 [POI2011] MET-Meteors
视频链接:C107 整体二分+树状数组(区修+点查)P3527 [POI2011] MET-Meteors_哔哩哔哩_bilibili
Luogu P3527 [POI2011] MET-Meteors
// 整体二分+树状数组(区修+点查)O(n*logm*logk) #include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define N 300005 #define LL long long #define lowbit(x) (x&-x) int h[N],to[N],ne[N],tot; void add(int a,int b){ //连边 to[++tot]=b;ne[tot]=h[a];h[a]=tot; } int n,m,k,p,x[N],y[N],a[N],ans[N]; struct Q{ int p,id; //国家希望陨石数,国家编号 }; vector<Q>q; struct BIT{ LL s[N<<1]; //维护2m段轨道的陨石数 void add(int x,int v){ while(x<=2*m) s[x]+=v,x+=lowbit(x); } LL sum(int x){ LL t=0; while(x) t+=s[x],x-=lowbit(x); return t; } }tree; //树状数组 void solve(vector<Q>q,int L,int R){ if(!q.size()) return; if(L==R){ for(auto i:q) ans[i.id]=L; //记录答案 return; } int mid=(L+R)>>1; //二分陨石雨次数 vector<Q>q1,q2; //分流国家序列 for(int i=L;i<=mid;i++) //差分贡献 tree.add(x[i],a[i]),tree.add(y[i]+1,-a[i]); for(auto i:q){ LL s=0; //累计国家i的陨石数 for(int j=h[i.id];j&&s<=i.p;j=ne[j]) s+=tree.sum(to[j])+tree.sum(to[j]+m); if(s>=i.p) q1.push_back(i); //分流到左边 else i.p-=s,q2.push_back(i); //分流到右边 } for(int i=L;i<=mid;i++) //清空贡献 tree.add(x[i],-a[i]),tree.add(y[i]+1,a[i]); solve(q1,L,mid); solve(q2,mid+1,R); //分治 } int main(){ scanf("%d%d",&n,&m); //n个国家, m段轨道 for(int i=1,o;i<=m;i++) scanf("%d",&o),add(o,i); //国家o向轨道i连边 for(int i=1;i<=n;i++) scanf("%d",&p),q.push_back({p,i}); //希望陨石数 scanf("%d",&k); for(int i=1;i<=k;i++) //[x,y]均落a个陨石 scanf("%d%d%d",&x[i],&y[i],&a[i]); for(int i=1;i<=k;i++) if(y[i]<x[i]) y[i]+=m; //破环成链 solve(q,1,k+1); //超过k次则被分裂到k+1节点 for(int i=1;i<=n;i++) ans[i]<=k?printf("%d\n",ans[i]):puts("NIE"); }
// 整体二分+树状数组 O(n*logm*logk) #include <iostream> #include <cstring> #include <algorithm> using namespace std; #define N 300005 #define LL long long #define lowbit(x) (x&-x) int h[N],to[N],ne[N],tot; void add(int a,int b){ //连边 to[++tot]=b;ne[tot]=h[a];h[a]=tot; } int n,m,k,x[N],y[N],a[N],ans[N]; struct Q{ int p,id; //国家希望陨石数,国家编号 }q[N],t[N]; struct BIT{ LL s[N<<1]; //维护2m段轨道的陨石数 void add(int x,int v){ while(x<=2*m) s[x]+=v,x+=lowbit(x); } LL sum(int x){ LL t=0; while(x) t+=s[x],x-=lowbit(x); return t; } }tree; //树状数组 void solve(int l,int r,int L,int R){ if(l>r)return; if(L==R){ for(int i=l;i<=r;i++) ans[q[i].id]=L; return; } int mid=(L+R)>>1; //二分陨石雨次数 int p1=l-1,p2=r+1; //分流国家序列 for(int i=L;i<=mid;i++) //差分贡献 tree.add(x[i],a[i]),tree.add(y[i]+1,-a[i]); for(int i=l;i<=r;i++){ LL s=0; //累计国家i的陨石数 for(int j=h[q[i].id];j&&s<=q[i].p;j=ne[j]) s+=tree.sum(to[j])+tree.sum(to[j]+m); if(s>=q[i].p) t[++p1]=q[i]; //分流到左边 else q[i].p-=s,t[--p2]=q[i]; //分流到右边 } for(int i=L;i<=mid;i++) //清空贡献 tree.add(x[i],-a[i]),tree.add(y[i]+1,a[i]); for(int i=l;i<=p1;i++) q[i]=t[i]; for(int i=p2;i<=r;i++) q[i]=t[r-i+p2]; //合流 solve(l,p1,L,mid); solve(p2,r,mid+1,R); //分治 } int main(){ scanf("%d%d",&n,&m); //n个国家, m段轨道 for(int i=1,o;i<=m;i++) scanf("%d",&o),add(o,i); //国家o向轨道i连边 for(int i=1;i<=n;i++) scanf("%d",&q[i].p),q[i].id=i; //希望陨石数 scanf("%d",&k); for(int i=1;i<=k;i++) //[x,y]均落a个陨石 scanf("%d%d%d",&x[i],&y[i],&a[i]); for(int i=1;i<=k;i++) if(y[i]<x[i]) y[i]+=m; //破环成链 solve(1,n,1,k+1); //超过k次则被分裂到k+1节点 for(int i=1;i<=n;i++) ans[i]<=k?printf("%d\n",ans[i]):puts("NIE"); }
分类:
C 数据结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2023-03-27 G58 尼姆(Nim)游戏