bzoj4399: 魔法少女LJJ
先上头图:
诈骗题认真读题 c<=7
只需要考虑前七个操作
一.动态开点即可
二.线段树合并
三.四.对于这两个操作,可以先统计出有多少个数小于/大于x,然后删除所有小于/大于x的数,并在x位置加上这些数
五.下放标记查询即可
六.每个数最大为1e9,直接乘肯定会炸,所以可以用double存它们的对数之积,log(nm)=log(n)+log(m)的性质可以很好地处理
七.直接查询即可
这题的思路还是非常简单的,主要在码出来
%%%%%%
调了两天半的代码:
#include <bits/stdc++.h> #define ls tree[gjd].lson #define rs tree[gjd].rson using namespace std; const int N=400010,inf=1e9; int x,a,b,k,m,ch,tot,cnt; int fa[N],rt[N]; struct stu{ int lson,rson,data;//data 存块数量 double sum;//求和 bool lazy;//标记 }tree[50*N]; int find(int x){ if(fa[x]==x) return x; return fa[x]=find(fa[x]); } void pushup(int gjd){ tree[gjd].data=tree[ls].data+tree[rs].data; tree[gjd].sum=tree[ls].sum+tree[rs].sum; } void pushdown(int gjd){ tree[ls].lazy=tree[rs].lazy=1; tree[ls].data=tree[rs].data=0; tree[ls].sum=tree[rs].sum=0; tree[gjd].lazy=0; } void insert(int &gjd,int l,int r,int now,int data,double sum){ if(!gjd) gjd=++cnt; tree[gjd].sum+=sum; tree[gjd].data+=data; if(l==r) return; if(tree[gjd].lazy) pushdown(gjd); int mid=(l+r)>>1; if(now<=mid) insert(ls,l,mid,now,data,sum); else insert(rs,mid+1,r,now,data,sum); } int update(int gjd,int l,int r,int x,int y){ if(x>y||!gjd) return 0; if(l==x&&r==y){ int p=tree[gjd].data; tree[gjd].data=0; tree[gjd].sum=0; tree[gjd].lazy=1; return p; } if(tree[gjd].lazy) pushdown(gjd); int mid=(l+r)>>1,ans; if(y<=mid) ans=update(ls,l,mid,x,y); else if(x>mid) ans=update(rs,mid+1,r,x,y); else ans=update(ls,l,mid,x,mid)+update(rs,mid+1,r,mid+1,y); pushup(gjd); return ans; } int queryk(int gjd,int l,int r,int k){ if(l==r) return l; if(tree[gjd].lazy) pushdown(gjd); int mid=(l+r)>>1; if(k<=tree[ls].data) return queryk(ls,l,mid,k); else return queryk(rs,mid+1,r,k-tree[ls].data); } int merge(int p,int q,int l,int r){ if(!p) return q; if(!q) return p; tree[p].data+=tree[q].data; tree[p].sum+=tree[q].sum; if(l<r){ if(tree[p].lazy) pushdown(p); if(tree[q].lazy) pushdown(q); int mid=(l+r)>>1; tree[p].lson=merge(tree[p].lson,tree[q].lson,l,mid); tree[p].rson=merge(tree[p].rson,tree[q].rson,mid+1,r); } return p; } int main(){ ios::sync_with_stdio(false); cin>>m; while(m--){ cin>>ch; //对于操作1、2、3、4、5、7,很容易想到使用并查集维护连通块, //对每个连通块开一棵权值线段树。 if(ch==1){ cin>>x; fa[++tot]=tot; insert(rt[tot],1,inf,x,1,log(x)); } else if(ch==2){ cin>>a>>b; a=find(a),b=find(b); if(a!=b) rt[a]=merge(rt[a],rt[b],1,inf); fa[b]=a; } //对于3、4操作,可以先统计出有多少个数小于/大于x, //然后删除所有小于/大于x的数,并在x位置加上这些数 else if(ch==3){ cin>>a>>x; a=find(a); int down=update(rt[a],1,inf,1,x-1); insert(rt[a],1,inf,x,down,down*log(x)); } else if(ch==4){ cin>>a>>x; a=find(a); int up=update(rt[a],1,inf,x+1,inf); insert(rt[a],1,inf,x,up,up*log(x)); } else if(ch==5){ cin>>a>>k; a=find(a); cout<<queryk(rt[a],1,inf,k)<<endl; } //取log(nm)=log(n)+log(m)处理乘法 else if(ch==6){ cin>>a>>b; a=find(a),b=find(b); if(tree[rt[a]].sum>tree[rt[b]].sum) cout<<"1"<<endl; else cout<<"0"<<endl; } else if(ch==7){ cin>>a; a=find(a); cout<<tree[rt[a]].data<<endl; } // else if(ch==8) cin>>a>>b; // else if(ch==9) cin>>a; } return 0; }
#一名爱打篮球的oier#
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】