2018.10.30 练习赛 T3 [Stark与Riga的卡牌游戏]-[zkw线段树嵌套map]
T3 Stark与Riga的卡牌游戏
题面:
题解:
注意到所有的询问都是以攻击力为询问的下标,考虑以攻击力为区间建立线段树;
显然,对于前三个操作,我们都可以将其转化为对线段树上元素的修改;
我们在每个叶子结点放上另一种数据结构,这种数据结构需要帮助我们快速取出最大最小的元素,这个实现的方法有很多,如:
用优先队列建立一个大根堆一个小根堆,分别对应两个垃圾堆用于将其变为可删除堆;
或者用\(set\)维护以\(A\)为下标的\(H\)有序,可快速取出\(*it,it=s.begin()/(--s.end())\),本文使用\(Map\)作为记录权值\(A\)中的元素个数;
对于区间最小最大的询问,我们将它用线段树动态维护,每次修改更新即可;
区间修改在外层线段树打上区间永久化标记,每次取出加上\(lazy\)值,加入新元素减去\(lazy\)值,删除指定元素减去\(lazy\)值;
这个实现的思路就和\(NOIP2016\)蚯蚓一样了\(qwq\)
\(zkw\)线段树优化常数,当然不写也是可以的;
\(code:\)
#include<cstdio>
#include<iostream>
#include<ctype.h>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<deque>
#include<algorithm>
#define reint register int
#define ll long long
#define ld double
#define l(x) (x<<1)
#define r(x) (x<<1|1)
#define rell register ll
#define mod 7528443412579576937ul
using namespace std;
char buf[1<<20],*p1,*p2;
inline char gc()
{
// return getchar();
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}
template<typename T>
inline void read(T &x)
{
char tt;
bool flag=0;
while(!isdigit(tt=gc())&&tt!='-');
tt=='-'?(flag=1,x=0):(x=tt-'0');
while(isdigit(tt=gc())) x=(x<<1)+(x<<3)+(tt^'0');
if(flag) x=-x;
}
const int maxn=1e5+2;
int n,m;
int M=1;
int lazy[maxn<<2];
int mx[maxn<<2],mi[maxn<<2];
map<int,int>a[maxn<<2];
map<int,int>b;
void pushdown(int x){
mi[x]=min(mi[l(x)]+lazy[l(x)],mi[r(x)]+lazy[r(x)]);
mx[x]=max(mx[l(x)]+lazy[l(x)],mx[r(x)]+lazy[r(x)]);
// printf("%d\n",mx[x]);
}
void update(int x){x+=M;while(x>>=1) pushdown(x);}
void modify(int x,int y,int d)
{
for(x+=M-1,y+=M+1;x^y^1;x>>=1,y>>=1)
{
if(x<M) pushdown(x);
if(y<M) pushdown(y);
if(~x&1) lazy[x^1]+=d;
if(y&1) lazy[y^1]+=d;
}
if(x<M) pushdown(x);
if(y<M) pushdown(y);
while(x>>=1) pushdown(x);
}
void modify(int x,int y)
{
int flag=0;
a[x][y]++;b[x]++;
if(mi[x+M]>y) mi[x+M]=y,flag=1;
if(mx[x+M]<y) mx[x+M]=y,flag=1;
if(flag) update(x);
}
int getlazy(int x,int sum=0)
{
x+=M;
do{
sum+=lazy[x];
x>>=1;
}while(x!=1);
return sum;
}
int getmin(int p,int l,int r,int x,int y)
{
if(x<=l&&y>=r) return mi[p]+lazy[p];
int mid=l+r>>1;
int ans=1e9;
if(x<=mid) ans=min(ans,getmin(l(p),l,mid,x,y));
if(y>mid) ans=min(ans,getmin(r(p),mid+1,r,x,y));
return ans+lazy[p];
}
int getmax(int p,int l,int r,int x,int y)
{
if(x<=l&&y>=r) return mx[p]+lazy[p];
int mid=l+r>>1;
int ans=-1e9;
if(x<=mid) ans=max(ans,getmax(l(p),l,mid,x,y));
if(y>mid) ans=max(ans,getmax(r(p),mid+1,r,x,y));
return ans+lazy[p];
}
void del(int x,int y)
{
bool flag=0;
b[x]--;if(b[x]==0) b.erase(x);a[x][y]--;
if(a[x][y]==0)
{
a[x].erase(y);
if(mi[x+M]==y)
{
if(a[x].size()==0) mi[x+M]=1e9;
else mi[x+M]=a[x].begin()->first;
flag=1;
}
if(mx[x+M]==y)
{
if(a[x].size()==0) mx[x+M]=-1e9;
else mx[x+M]=(--a[x].end())->first;
flag=1;
}
if(flag) update(x);
}
}
int main()
{
// freopen("23.txt","w",stdout);
while(M<=maxn)M<<=1;
read(n),read(m);
for(int i=M;i<M<<1;i++)
mi[i]=1e9,mx[i]=-1e9;
for(int i=1;i<=n;i++)
{
int x,y;
read(x),read(y);
a[x][y]++,b[x]++;
mi[x+M]=min(mi[x+M],y),
mx[x+M]=max(mx[x+M],y);
}
for(int i=M-1;i>=1;i--) pushdown(i);
while(m--)
{
int opt1,opt2;
int x,y,z;
read(opt1),read(opt2);
read(x),read(y);
if(opt1==1&&opt2==1) read(z);
if(opt1==0)
{
if(opt2==1)
{
auto it1=b.lower_bound(y);
auto it2=--a[it1->first].end();
int tx=it1->first,ty=it2->first;
int tmp=getlazy(tx);
del(tx,ty);ty-=x;
if(ty+tmp>0) modify(tx,ty);
}
if(opt2==2)
{
auto it1=b.lower_bound(y);
auto it2=a[it1->first].begin();
int tx=it1->first,ty=it2->first;
del(tx,ty);
}
if(opt2==3)
{
// if(x==5&&y==9) printf("**%d\n",y-getlazy(x));
del(x,y-getlazy(x));
}
}
if(opt1==1)
{
if(opt2==1) modify(x,y,z);
if(opt2==2) printf("%d\n",getmax(1,0,M-1,x,y)+getmin(1,0,M-1,x,y));
if(opt2==3) modify(x,y-getlazy(x));
}
// printf("233_____________:%d\n",getlazy(7));
}
}