当前位置:网站首页>权值线段树+线段树分裂/合并+CF1659D
权值线段树+线段树分裂/合并+CF1659D
2022-07-30 04:10:00 【追随远方的某R】
如果一个01数组A进行n次排序,第i次sort前i个,过程中可形成n个序列,将这些序列的对应为相加形成一个新的序列C。
现在给定C,求符合要求的原序列A
题目的情景设的比较特殊,有一种比较巧妙的构造方法,分析了每个位置的1对前后的贡献。
重要的一点是:如果这个位置是0,但是对应的c数组这个位置有值,那么应当能得出结论,次位置后的C[i]-1个位置均为1.
#include <iostream>
#define endl '\n'
using namespace std;
const int N=2e5+100;
int a[N],b[N];
int main()
{
int t;
for(cin>>t;t;t--)
{
int n,p=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=0;
}
for(int i=1;i<=n;i++)
{
if(p<i)
{
if(a[i])
b[i]=1;
else
b[i]=0;
}
if(b[i]==1)
{
for(++p;p<=a[i];++p)
b[p]=1;
b[p]=0;
}
else
{
for(++p;p<=a[i]+i-1;++p)
b[p]=1;
b[p]=0;
}
}
for(int i=1;i<=n;i++)
cout<<b[i]<<" ";
cout<<endl;
}
return 0;
}
关于分裂操作的理解果然还不是很透彻,还需要多琢磨一下,其他的方面都是常见的操作比如:动态开点,n颗线段树啊之类的,还有权值线段树的一些操作。
#include <bits/stdc++.h>
#define int long long
#define ls lson[rt]
#define rs rson[rt]
#define mid ((l+r)>>1)
#define endl '\n'
#define fastio cout.tie(0);cin.tie(0);ios::sync_with_stdio(0)
using namespace std;
const int N = 2e5+100;
int gra[N<<5],tree[N<<5],lson[N<<5],rson[N<<5],cnt,tot,root[N<<5],a[N],seq=1,n,m;
int new_node()
{
return cnt?gra[cnt--]:++tot;
}
void del_node(int p)
{
gra[++cnt]=p;
tree[p]=0;lson[p]=0;rson[p]=0;
return ;
}
void fix(int &rt,int l,int r,int num,int x)
{
if(!rt)
rt=new_node();
tree[rt]+=x;
if(l==r)
return ;
if(num<=mid)
fix(ls,l,mid,num,x);
else
fix(rs,mid+1,r,num,x);
}
int query_num(int rt,int l,int r,int nl,int nr)
{
if(l>nr||r<nl)
return 0;
if(nl<=l&&r<=nr)
return tree[rt];
return query_num(ls,l,mid,nl,nr)+query_num(rs,mid+1,r,nl,nr);
}
int query_kth(int rt,int l,int r,int num)
{
if(l==r)
return l;
if(tree[ls]>=num)
return query_kth(ls,l,mid,num);
else
return query_kth(rs,mid+1,r,num-tree[ls]);
}
int merge(int x,int y)
{
if(!x||!y)
return x+y;
tree[x]+=tree[y];
lson[x]=merge(lson[x],lson[y]);
rson[x]=merge(rson[x],rson[y]);
del_node(y);
return x;
}
void split(int x,int &y,int k)
{
if(x==0)
return;
y=new_node();
int v=tree[lson[x]];
if(k>v)
split(rson[x],rson[y],k-v);
else
swap(rson[x],rson[y]);
if(k<v)
split(lson[x],lson[y],k);
tree[y]=tree[x]-k;
tree[x]=k;
return ;
}
signed main()
{
//fastio;
cin>>n>>m;
for(int i=1,temp;i<=n;i++)
{
cin>>temp;
fix(root[1],1,n,i,temp);
}
for(int i=1,op,p,k,x,q,y,t;i<=m;i++)
{
cin>>op;
if(op==0)
{
cin>>p>>x>>y;
int k1=query_num(root[p],1,n,1,y);
int k2=query_num(root[p],1,n,x,y);
int temp=0;
split(root[p],root[++seq],k1-k2);
split(root[seq],temp,k2);
root[p]=merge(root[p],temp);
}
if(op==1)
{
cin>>p>>t;
root[p]=merge(root[p],root[t]);
}
if(op==2)
{
cin>>p>>x>>q;
fix(root[p],1,n,q,x);
}
if(op==3)
{
cin>>p>>x>>y;
cout<<query_num(root[p],1,n,x,y)<<endl;
}
if(op==4)
{
cin>>p>>k;
if(tree[root[p]]<k)
{
cout<<-1<<endl;
continue;
}
cout<<query_kth(root[p],1,n,k)<<endl;
}
}
return 0;
}
/* 5 12 0 0 0 0 0 2 1 1 1 2 1 1 2 2 1 1 3 3 1 1 3 4 1 2 2 1 1 4 2 1 1 5 0 1 2 4 2 2 1 4 3 2 2 4 1 1 2 4 1 3 */
权值线段树,我理解的是可重集的线段树。给定了一个无序的数组,在若干个插入操作之后构造出一颗有序的线段树,每个节点代表这个区间有多少值,叶子节点就代表了每个值的出现次数。
常见的操作有:
离散化,动态开点,查询区间第k小/大,查询区间有多少数,增加/删除x个点/数。
#include<bits/stdc++.h>
#define ls lson[rt]
#define rs rson[rt]
#define mid ((l+r)>>1)
using namespace std;
const int N = 1e7+100;
int m;
int lson[N<<2],rson[N<<2],tree[N<<2],cnt,root;
void up(int rt)
{
tree[rt]=tree[ls]+tree[rs];
}
void fix(int &rt,int l,int r,int p,int v)
{
if(!rt)
{
rt=++cnt;
}
if(l==r)
{
tree[rt]+=v;
return ;
}
if(p<=mid)
fix(ls,l,mid,p,v);
if(p>mid)
fix(rs,mid+1,r,p,v);
up(rt);
}
int query_num(int rt,int l,int r,int pl,int pr)
{
int ans=0;
if(pl<=l&&r<=pr)
return tree[rt];
if(pl<=mid)
ans+=query_num(ls,l,mid,pl,pr);
if(pr>mid)
ans+=query_num(rs,mid+1,r,pl,pr);
return ans;
}
int query_kth(int rt,int l,int r,int k)
{
if(l==r)
return l;
int s=tree[ls];
if(k<=s)
return query_kth(ls,l,mid,k);
else
return query_kth(rs,mid+1,r,k-s);
}
map<int,int> ma;
int main()
{
scanf("%d",&m);
while(m--)
{
int opt,x;scanf("%d%d",&opt,&x);
if(opt==1)
{
fix(root,1,N*2,x+N,1);//题目中给出的是绝对值小于等于1e7所以这里要把负数值域搬到正数来
ma[x]++;
}
if(opt==2)
{
fix(root,1,N*2,x+N,-1);
ma[x]--;
if(ma[x]==0)
ma.erase(x);
}
if(opt==3)
{
printf("%d\n",query_num(root,1,N*2,1,x+N-1)+1);
}
if(opt==4)
{
printf("%d\n",query_kth(root,1,N*2,x)-N);
}
if(opt==5)
printf("%d\n",(--ma.lower_bound(x))->first);
if(opt==6)
printf("%d\n",(ma.upper_bound(x))->first);
}
return 0;
}
边栏推荐
- Flutter record learning different animation (2)
- When the EasyNVR platform is cascaded to the EasyCVR, why can't the video be played after a while?
- PyG builds R-GCN to realize node classification
- TCP congestion control technology and acceleration principle of BBR
- Redis server启动后会做哪些操作?
- Mysql version upgrade, copy the Data file directly, the query is very slow
- JQ source code analysis (environment)
- Wechat second-hand transaction small program graduation design finished product (1) Development overview
- 骁龙7系芯片表现如何?Reno8 Pro佐证新一代神U
- Summary of Rpc and gRpc Introduction
猜你喜欢

Pytorch框架学习记录2——TensorBoard的使用

sqlmap use tutorial Daquan command Daquan (graphics)

Resampling a uniformly sampled signal

新型LaaS协议Elephant Swap给ePLATO提供可持续溢价空间

Mini Program Graduation Works WeChat Second-hand Trading Mini Program Graduation Design Finished Work (2) Mini Program Function

spicy (1) basic definition

PyG搭建R-GCN实现节点分类

宇宙的尽头是银行?聊聊在银行做软件测试的那些事

国内首家沉浸式高逼真元宇宙,希元宇宙正式上线

Shell脚本基本编辑规范及变量
随机推荐
Let's learn the layout components of flutter together
How does the AI intelligent security video platform EasyCVR configure the simultaneous transmission of audio and video?
Redis【超详解!!!】
Tcp programming
[ 云原生之谜 ] 云原生背景 && 定义 && 相关技术详解?
Pytorch framework learning record 2 - the use of TensorBoard
[The Mystery of Cloud Native] Cloud Native Background && Definition && Detailed explanation of related technologies?
How to Effectively Conduct Retrospective Meetings (Part 1)?
SQLSERVER merges subquery data into one field
CMake installation and testing
【C进阶】数组传参与函数指针
ospf 导图
智能答题功能,CRMEB知识付费系统必须有!
Mysql版本升级,直接复制Data文件,查询特别慢
Roperties类配置文件&DOS查看主机网络情况
WEB penetration of information collection
小程序毕设作品之微信积分商城小程序毕业设计成品(2)小程序功能
Why is the Kirin 9000 5G version suddenly back in stock?
Taobao/Tmall get the list of sold product orders API
为什么突然间麒麟 9000 5G 版本,又有库存了?