线段树分治学习笔记
1.一种数据结构,一般用于有撤销操作,并且不好处理撤销的题目中。这个时候对时间建立线段树,将每个修改和询问插入对应时间内,对每个线段树节点进行处理就可以保证时间复杂度为 \( \O (nlogn) \) 。
2.例题
(1)
P5787 二分图 /【模板】线段树分治
题意:给出n个点,m条边,每条边从时间l出现,r消失,求每个时间图是否是二分图。
题解:
二分图的判定可以通过判断奇环来搞,判奇环可以使用扩展域并查集。
进行线段树分治,将每条边插入对应时间的节点vector中, 到了一个节点后使用可撤销并查集将所有该节点的的边处理了,递归结束时将边的贡献撤销即可。(使用一个栈记录每次操作前的状态)。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int k,n,m,fa[N],u[N],v[N],dep[N];
vector <int> ve[N<<1];
struct pigu
{
int xp,shu;
pigu(int x=0,int y=0)
{
shu=x;xp=y;
}
};
inline int read()
{
char c=getchar();
int x=0,f=1;
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*f;
}
inline void insert(int now,int l,int r,int L,int R,int jia)
{
if(l>=L&&r<=R)
{
ve[now].push_back(jia);
return;
}
int mid=(l+r)>>1;
if(L<=mid) insert(now<<1,l,mid,L,R,jia);
if(R>=mid+1) insert(now<<1|1,mid+1,r,L,R,jia);
}
stack <pigu> st;
inline int find(int x)
{
if(x==fa[x]) return x;
return find(fa[x]);
}
inline void merge(int x,int y)
{
if(x==y) return;
if(dep[x]<dep[y]) swap(x,y);
st.push(pigu(y,dep[x]==dep[y]));
fa[y]=x;dep[x]+=(dep[x]==dep[y]);
}
inline void get_ans(int now,int l,int r)
{
bool pan=0;
int len=ve[now].size(),hu=st.size();
for(int i=0;i<len;i++)
{
int fa1=find(u[ve[now][i]]),fa2=find(v[ve[now][i]]);
if(fa1==fa2)
{
for(int j=l;j<=r;j++)
cout<<"No\n";
pan=1;
break;
}
merge(find(u[ve[now][i]]+n),fa2);merge(find(v[ve[now][i]]+n),fa1);
}
if(pan==0)
{
int mid=(l+r)>>1;
if(l==r) cout<<"Yes\n";
else
{
get_ans(now<<1,l,mid);
get_ans(now<<1|1,mid+1,r);
}
}
while(st.size()>hu)
{
dep[fa[st.top().shu]]-=st.top().xp;
fa[st.top().shu]=st.top().shu;
st.pop();
}
}
int main()
{
n=read();m=read();k=read();
for(int i=1;i<=2*n;i++) fa[i]=i;
for(int i=1,l,r;i<=m;i++)
{
u[i]=read();v[i]=read();l=read();r=read();
if(l<r) insert(1,1,k,l+1,r,i);
}
get_ans(1,1,k);
}
由于y,z可以随便定,故他们不起作用。
只需要考虑插入删除了一个二元组(x,c)。
查询给出X,求最小的 \( (X-x)^{2} + c \) 即可。
题解
设所求结果为y将狮子化简得到 \( (xi)^{2}+c_i=2*X*x_i-X^{2}+y \) 使截距最小。
将询问按X排序,插入按x排序后,维护斜率单调递增的凸包就完了。
代码如下:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5;
const int inf=1e18;
const double eps=1e-8;
int n,m,ans[N],c[N],last[N],size,dx[N],dui[N],b[N];
struct pigu
{
int dao,ne;
}a[N];
struct dapigu
{
int hao,x,id;
}wen[N];
inline bool cmp1(dapigu x,dapigu y)
{
return x.x<y.x;
}
vector <int> qjl[N],qjr[N],q[N<<2];
inline void lingjiebiao(int x,int y)
{
a[++size].dao=y;
a[size].ne=last[x];
last[x]=size;
}
inline bool cmp(int x,int y)
{
return dx[x]<dx[y];
}
int h[N<<2],t[N<<2],dfn[N],cnt;
inline void dfs(int now)
{
dfn[now]=++cnt;
if(dui[now]>0) qjl[dui[now]].push_back(cnt);
if(dui[now]<0) qjr[-dui[now]].push_back(cnt-1);
for(int i=last[now];i;i=a[i].ne) dfs(a[i].dao);
if(dui[now]>0) qjr[dui[now]].push_back(cnt);
if(dui[now]<0) qjl[-dui[now]].push_back(cnt+1);
}
inline void build(int now,int l,int r)
{
h[now]=0;t[now]=-1;
if(l==r) return;
int mid=(l+r)>>1;
build(now<<1,l,mid);build(now<<1|1,mid+1,r);
}
inline double xl(int x,int y)
{
return (double)((double)(dx[x]*dx[x]-dx[y]*dx[y]+c[x]-c[y])/(double)(dx[x]-dx[y]));
}
inline void update(int now,int l,int r,int L,int R,int zai)
{
if(l>=L&&r<=R)
{
while(q[now].size()<t[now]+5) q[now].push_back(0);
if(t[now]>=0&&dx[q[now][t[now]]]==dx[zai])
{
if(c[zai]>=c[q[now][t[now]]]) return;
t[now]--;
}
while(h[now]<t[now]&&xl(zai,q[now][t[now]])<xl(q[now][t[now]],q[now][t[now]-1])) t[now]--;
q[now][++t[now]]=zai;
return;
}
int mid=(l+r)>>1;
if(L<=mid) update(now<<1,l,mid,L,R,zai);
if(R>=mid+1) update(now<<1|1,mid+1,r,L,R,zai);
}
inline int query(int now,int l,int r,int zai,int x,int res)
{
while(h[now]<t[now]&&xl(q[now][h[now]+1],q[now][h[now]])<2.0*x+eps) h[now]++;
if(h[now]<=t[now]) res=min(res,(x-dx[q[now][h[now]]])*(x-dx[q[now][h[now]]])+c[q[now][h[now]]]);
if(l==r) return res;
int mid=(l+r)>>1;
if(zai<=mid) return query(now<<1,l,mid,zai,x,res);
return query(now<<1|1,mid+1,r,zai,x,res);
}
inline int read()
{
char c=getchar();
int x=0,f=1;
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*f;
}
signed main()
{
n=read();m=read();c[0]=read();
for(int i=1,opt,co,hao,y,z;i<=n-1;i++)
{
opt=read();
if(opt==0)
{
co=read();hao=read();dx[hao]=read();y=read();z=read();c[hao]=read();
dui[i]=hao;
}
else
{
co=read();hao=read();
dui[i]=-hao;
}
lingjiebiao(co,i);
}
dfs(0);
build(1,1,n);
for(int i=1;i<=n;i++) b[i]=i;
sort(b+1,b+n+1,cmp);
update(1,1,n,1,n,0);
for(int i=1;i<=n;i++)
{
int x=b[i];
for(int j=0;j<qjl[x].size();j++)
{
if(qjl[x][j]<=qjr[x][j]) update(1,1,n,qjl[x][j],qjr[x][j],x);
}
}
for(int i=1;i<=m;i++)
{
wen[i].hao=read();wen[i].x=read();
wen[i].id=i;
}
sort(wen+1,wen+m+1,cmp1);
for(int i=1;i<=m;i++)
{
ans[wen[i].id]=query(1,1,n,dfn[wen[i].hao],wen[i].x,inf);
}
for(int i=1;i<=m;i++) cout<<ans[i]<<"\n";
}
将商店按照编号排序,然后插入每个对应线段树节点的可持久化trie中,再将询问插入所有对应的时间中,在每个时间都跑一遍异或最大值即可。
复杂度 \( n ( log_2 {n} ) ^{2} \)
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
int n,m,rt[N],hav[N],cnt1,cnt2,ans[N];
struct trie
{
int l,r,siz;
}a[N*20];
vector <int> ve[N<<2];
struct dapigu
{
int di,val,t;
dapigu(int x=0,int y=0,int z=0)
{
di=y;val=x;t=z;
}
}jia[N],zuo[N],you[N];
struct xunwen
{
int l,r,tr,tl,val;
xunwen(int x=0,int y=0,int z=0,int u=0,int w=0)
{
l=x;r=y;tl=z;tr=u;val=w;
}
}wen[N];
inline int read()
{
char c=getchar();
int x=0,f=1;
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*f;
}
int cnt,daan;
inline void insert(int &now,int pre,int zhi,int xz)
{
now=++cnt;
a[now]=a[pre];
a[now].siz++;
if(xz==-1) return;
int pan=zhi&(1<<xz);
if(!pan) insert(a[now].l,a[pre].l,zhi,xz-1);
else insert(a[now].r,a[pre].r,zhi,xz-1);
}
inline void update(int now,int l,int r,int L,int R,int xy)
{
if(L>R||r<L||l>R) return;
if(L<=l&&r<=R) {ve[now].push_back(xy);return;}
int mid=(l+r)>>1;
update(now<<1,l,mid,L,R,xy);
update(now<<1|1,mid+1,r,L,R,xy);
}
inline void query(int now,int pre,int x,int xz)
{
if(xz==-1) return;
int pan=(1<<xz)&x;
if(pan==0)
{
if(a[a[now].r].siz-a[a[pre].r].siz) daan|=(1<<xz),query(a[now].r,a[pre].r,x,xz-1);
else query(a[now].l,a[pre].l,x,xz-1);
}
else
{
if(a[a[now].l].siz-a[a[pre].l].siz) daan|=(1<<xz),query(a[now].l,a[pre].l,x,xz-1);
else query(a[now].r,a[pre].r,x,xz-1);
}
}
inline bool cmp(dapigu x,dapigu y)
{
return x.di<y.di;
}
inline void calc(int now,int L,int R)
{
int top=0;cnt=0;
for(int i=L;i<=R;i++)
{
hav[++top]=jia[i].di;
insert(rt[top],rt[top-1],jia[i].val,20);
}
int len=ve[now].size();
for(int i=0;i<len;i++)
{
int shi=ve[now][i];
int ll=upper_bound(hav+1,hav+top+1,wen[shi].l-1)-hav-1;
int rr=upper_bound(hav+1,hav+top+1,wen[shi].r)-hav-1;
daan=0;
query(rt[rr],rt[ll],wen[shi].val,20);
ans[shi]=max(ans[shi],daan);
}
}
inline void fenzhi(int now,int l,int r,int L,int R)
{
if(L>R)return;
int cn1=0,cn2=0;
calc(now,L,R);
if(l==r)return;
int mid=(l+r)>>1;
for(int i=L;i<=R;i++)
if(jia[i].t<=mid)zuo[++cn1]=jia[i];
else you[++cn2]=jia[i];
for(int i=1;i<=cn1;i++)jia[i+L-1]=zuo[i];
for(int i=1;i<=cn2;i++)jia[i+L-1+cn1]=you[i];
fenzhi(now<<1,l,mid,L,L+cn1-1);
fenzhi(now<<1|1,mid+1,r,L+cn1,R);
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++) insert(rt[i],rt[i-1],read(),20);
for(int i=1,opt,x,y,z,w;i<=m;i++)
{
opt=read();
if(opt==0)
{
x=read();y=read();cnt1++;
jia[cnt1]=dapigu(y,x,cnt1);
}
else
{
x=read();y=read();z=read();w=read();
wen[++cnt2]=xunwen(x,y,max(1,cnt1-w+1),cnt1,z);
daan=0;query(rt[y],rt[x-1],z,20);
ans[cnt2]=daan;
}
}
for(int i=1;i<=cnt2;i++) update(1,1,cnt1,wen[i].tl,wen[i].tr,i);
sort(jia+1,jia+cnt1+1,cmp);
fenzhi(1,1,cnt1,1,cnt1);
for(int i=1;i<=cnt2;i++) cout<<ans[i]<<"\n";
}
做过WC的最大异或路径就可以晓得从起点出发找到几个环异或完了归起点,最后走一条路直接到终点。
因为从起点到环上的点的路径会经过两次就异或来莫得了。并且最后的一条路是任意一条路都可以,因为如果走不同的路那两条路径间就会构成一些环,将这些换异或掉就得到了之前的路径。
将所有路径插到对应时间内,使用并查集搞,如果两个不连通就联通就把他们的跟的边权赋为w1^w2^bi[i].quan,不难发现这样和将这两个点相连是等价的。(w1w2为这两个点到根的异或和)。
如果连通就把当前这一层的线性基用边权w1^w2^bi[i].quan更新。
最终查询出来两个到根距离异或和弄到线性基头反手一搞就得到答案并输出。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=400005;
map<int,int> ma[N];
int n,m,q,sj,cnt;
struct guapi {int fa,qu,siz;}bc[N];
struct bian
{
int co,dao,l,r,w;
}a[N];
struct xunwenxunwen
{
int x,y;
}xw[N];
struct xianxingji
{
int p[32];
inline void add(int x)
{
for(int i=31;i>=0;i--)
{
if((1<<i)&x)
{
if(!p[i])
{
p[i]=x;
break;
}
else x^=p[i];
}
}
}
}ji[22];
vector <int> wen[N],ve[N<<2];
inline void update(int now,int l,int r,int L,int R,int x)
{
if(L<=l&&r<=R)
{
ve[now].push_back(x);
return;
}
int mid=(l+r)>>1;
if(L<=mid) update(now<<1,l,mid,L,R,x);
if(mid+1<=R) update(now<<1|1,mid+1,r,L,R,x);
}
inline int read()
{
char c=getchar();
int x=0,f=1;
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*f;
}
inline int find(int x,int &w)
{
while(x!=bc[x].fa)
{
w^=bc[x].qu;
x=bc[x].fa;
}
return x;
}
stack < pair < int , int > > st;
stack <guapi> stt;
inline void merge(int x,int y,int w,int dep)
{
if(x==y) ji[dep].add(w);
else
{
if(bc[x].siz<bc[y].siz) swap(x,y);
st.push(make_pair(y,bc[y].siz==bc[x].siz));stt.push(bc[y]);
bc[y].qu=w;bc[y].fa=x;
if(bc[y].siz==bc[x].siz) bc[x].siz++;
}
}
inline int query1(int dep,int zhi)
{
for(int i=31;i>=0;i--)
if(zhi&(1<<i))
zhi^=ji[dep].p[i];
return zhi;
}
inline int query(int x,int y,int dep)
{
int w=0;
find(x,w);find(y,w);
return query1(dep,w);
}
inline void insert(int now,int dep)
{
int len=ve[now].size();
for(int i=0;i<len;i++)
{
int x=a[ve[now][i]].co,y=a[ve[now][i]].dao,w1=0,w2=0;
x=find(x,w1);y=find(y,w2);
merge(x,y,w1^w2^a[ve[now][i]].w,dep);
}
}
inline void solve(int now,int l,int r,int dep)
{
ji[dep]=ji[dep-1];
int fuck=st.size();
insert(now,dep);
if(l==r)
{
int len=wen[l].size();
for(int i=0;i<len;i++)
cout<<query(xw[wen[l][i]].x,xw[wen[l][i]].y,dep)<<"\n";
return;
}
int mid=(l+r)>>1;
solve(now<<1,l,mid,dep+1);
solve(now<<1|1,mid+1,r,dep+1);
while(st.size()>fuck) bc[bc[st.top().first].fa].siz-=st.top().second,bc[st.top().first]=stt.top(),st.pop(),stt.pop();
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;i++)
{
a[i].co=read();a[i].dao=read();a[i].w=read();a[i].l=1;
if(a[i].co>a[i].dao) swap(a[i].co,a[i].dao);
ma[a[i].co][a[i].dao]=i;
}
for(int i=1;i<=n;i++) bc[i].fa=i;
q=read();sj=1;
for(int i=1,opt,x,y,z;i<=q;i++)
{
opt=read();x=read();y=read();
if(opt==1)
{
z=read();sj++;
if(x>y) swap(x,y);
a[++m].co=x;a[m].dao=y;a[m].l=sj;a[m].w=z;
ma[x][y]=m;
}
if(opt==2)
{
if(x>y) swap(x,y);
a[ma[x][y]].r=sj;
sj++;
}
if(opt==3)
{
xw[++cnt].x=x;xw[cnt].y=y;
wen[sj].push_back(cnt);
}
}
for(int i=1;i<=m;i++) update(1,1,sj,a[i].l,a[i].r?a[i].r:sj,i);
solve(1,1,sj,1);
}
根上头那个题一样的就是换成求异或最大值,然后线性基用一个bitset维护就可以了。
代码如下:
#include<bits/stdc++.h>
#define bs bitset <1005>
using namespace std;
const int N=4005;
int n,m,cnt,cnt1,p,malen;
string s;
struct pigu
{
int co,dao,l,r;
bitset <1005> bi;
}a[N<<1];
struct guapi
{
int fa,siz;
bs qu;
}bc[N];
struct xianxingji
{
bs p[1005];
}ji[20];
stack < pair < int , int > > st;
stack <guapi> stt;
vector <int> ve[N];
inline void update(int now,int l,int r,int L,int R,int x)
{
if(l>=L&&r<=R)
{
ve[now].push_back(x);
return;
}
int mid=(l+r)>>1;
if(L<=mid) update(now<<1,l,mid,L,R,x);
if(R>=mid+1) update(now<<1|1,mid+1,r,L,R,x);
}
inline int read()
{
char c=getchar();
int x=0,f=1;
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*f;
}
inline void print(bs x)
{
int pan=0;
for(int i=malen;i>=0;i--)
{
if(x[i]) pan=1;
if(pan) putchar(x[i]+'0');
}
if(!pan) putchar('0');
cout<<"\n";
}
inline int query(int x)
{
bs ans;ans.reset();
for(int i=malen;i>=0;i--) if(!ans[i]) ans^=ji[x].p[i];
print(ans);
}
inline int find(int x,bs &w)
{
while(x!=bc[x].fa)
{
w^=bc[x].qu;
x=bc[x].fa;
}
return x;
}
inline void add(int dep,bs x)
{
for(int i=malen;i>=0;i--)
if(x[i])
{
if(!ji[dep].p[i].any())
{
ji[dep].p[i]=x;
break;
}
else x^=ji[dep].p[i];
}
}
inline void insert(int now,int dep)
{
int len=ve[now].size();
for(int i=0;i<len;i++)
{
int dq=ve[now][i];
bs w1(0),w2(0);
int x=find(a[dq].co,w1),y=find(a[dq].dao,w2);
if(x==y)
{
add(dep,w1^w2^a[dq].bi);
continue;
}
if(bc[x].siz<bc[y].siz) swap(x,y);
st.push(make_pair(y,bc[x].siz==bc[y].siz)),stt.push(bc[y]);
bc[y].fa=x;bc[y].qu=w1^w2^a[dq].bi;bc[x].siz+=(bc[x].siz==bc[y].siz);
}
}
inline void solve(int now,int l,int r,int dep)
{
int sizn=st.size();
ji[dep]=ji[dep-1];
insert(now,dep);
if(l==r)
{
query(dep);
return;
}
int mid=(l+r)>>1;
solve(now<<1,l,mid,dep+1);
solve(now<<1|1,mid+1,r,dep+1);
while(st.size()>sizn) bc[bc[st.top().first].fa].siz-=st.top().second,bc[st.top().first]=stt.top(),st.pop(),stt.pop();
}
char c[10];
int main()
{
n=read();m=read();p=read();
for(int i=1;i<=n;i++) bc[i].fa=i;
for(int i=1;i<=m;i++)
{
a[i].co=read();a[i].dao=read();
cin>>s;int len=s.size();malen=max(malen,len);
a[i].bi= bs(s);
update(1,1,p+1,1,p+1,i);
}cnt=m;cnt1=m+p+1;
for(int i=1,opt,x,y,z;i<=p;i++)
{
scanf("%s",c+1);
if(c[2]=='d')
{
x=read();y=read();cin>>s;int len=s.size();malen=max(malen,len);
a[++cnt].co=x;a[cnt].dao=y;a[cnt].bi=bs(s);
a[cnt].l=i+1;
}
if(c[2]=='a')
{
x=read();
a[x+m].r=i;
}
if(c[2]=='h')
{
x=read();cin>>s;int len=s.size();
a[x+m].r=i;malen=max(malen,len);
a[++cnt1]=a[x+m];
update(1,1,p+1,a[x+m].l,a[x+m].r,cnt1);
a[x+m].l=i+1;a[x+m].bi=bs(s);
a[x+m].r=0;
}
}
for(int i=m+1;i<=cnt;i++)
update(1,1,p+1,a[i].l,a[i].r?a[i].r:p+1,i);
solve(1,1,p+1,1);
}
发现当k>0时,可以将所有点按照x升序排序,发现后头的在k达到某个值之后就会永远大于前头的点,然后就可以求出每个相邻的大小互换的最小的k,再将所有大于0的k按升序排序,大于了队首的值就把队首出队即可。
k<0时也差不多,反正写两个就完了。
代码如下:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+5;
const int inf=9000000000000000000;
const int xiinf=1e9+5;
int n,dui[N],cnt,cnt1,ma[N<<2],pan[N],h[N<<2],t[N<<2],cnt2,gudan,ans[N];
struct pigu
{
int x,y,l,r;
}a[N];
struct xunwen
{
int k,t,id;
}wen[N],wen1[N];
inline int cmp(pigu x,pigu y)
{
return x.x<y.x;
}
inline int cmp1(xunwen x,xunwen y)
{
return x.k<y.k;
}
inline int cmp2(xunwen x,xunwen y)
{
return x.k>y.k;
}
inline int cmp3(pigu x,pigu y)
{
return x.x>y.x;
}
inline int read()
{
char c=getchar();
int x=0,f=1;
while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
return x*f;
}
vector <int> que[N<<2];
inline void build(int now,int l,int r)
{
ma[now]=-inf;h[now]=0;t[now]=-1;que[now].clear();
if(l==r) return;
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
}
inline int suan(int x,int y)
{
int l=1,r=xiinf,daan=xiinf;
while(l<=r)
{
int mid=(l+r)>>1;
if(mid*a[x].x+a[x].y>=mid*a[y].x+a[y].y) r=mid-1,daan=mid;
else l=mid+1;
}
return daan;
}
inline int suan1(int x,int y)
{
int l=-xiinf,r=-1,daan=-xiinf;
while(l<=r)
{
int mid=(l+r)>>1;
if(mid*a[x].x+a[x].y>=mid*a[y].x+a[y].y) l=mid+1,daan=mid;
else r=mid-1;
}
return daan;
}
inline void update(int now,int l,int r,int L,int R,int x)
{
if(l>=L&&r<=R)
{
ma[now]=max(ma[now],a[x].y);
while(que[now].size()<t[now]+5) que[now].push_back(0);
while(h[now]<t[now]&&(a[x].y>=a[que[now][t[now]]].y||suan(x,que[now][t[now]])<=suan(que[now][t[now]],que[now][t[now]-1])))t[now]--;
que[now][++t[now]]=x;
return;
}
int mid=(l+r)>>1;
if(L<=mid) update(now<<1,l,mid,L,R,x);
if(R>=mid+1) update(now<<1|1,mid+1,r,L,R,x);
}
inline void query(int now,int l,int r,int zai,int x)
{
if(x==0) gudan=max(gudan,ma[now]);
else
{
while(h[now]<t[now]&&suan(que[now][h[now]+1],que[now][h[now]])<=x) h[now]++;
if(h[now]<=t[now]) gudan=max(gudan,x*a[que[now][h[now]]].x+a[que[now][h[now]]].y);
}
if(l==r) return;
int mid=(l+r)>>1;
if(zai<=mid) query(now<<1,l,mid,zai,x);
else query(now<<1|1,mid+1,r,zai,x);
}
inline void update1(int now,int l,int r,int L,int R,int x)
{
if(l>=L&&r<=R)
{
ma[now]=max(ma[now],a[x].y);
while(que[now].size()<t[now]+5) que[now].push_back(0);
while(h[now]<t[now]&&(a[x].y>=a[que[now][t[now]]].y||suan1(x,que[now][t[now]])>=suan1(que[now][t[now]],que[now][t[now]-1])))t[now]--;
que[now][++t[now]]=x;
return;
}
int mid=(l+r)>>1;
if(L<=mid) update1(now<<1,l,mid,L,R,x);
if(R>=mid+1) update1(now<<1|1,mid+1,r,L,R,x);
}
inline void query1(int now,int l,int r,int zai,int x)
{
if(x==0) gudan=max(gudan,ma[now]);
else
{
while(h[now]<t[now]&&suan1(que[now][h[now]+1],que[now][h[now]])>=x) h[now]++;
if(h[now]<=t[now]) gudan=max(gudan,x*a[que[now][h[now]]].x+a[que[now][h[now]]].y);
}
if(l==r) return;
int mid=(l+r)>>1;
if(zai<=mid) query1(now<<1,l,mid,zai,x);
else query1(now<<1|1,mid+1,r,zai,x);
}
signed main()
{
n=read();
for(int i=1,x,y,opt;i<=n;i++)
{
opt=read();
if(opt==1)
{
x=read();y=read();
a[++cnt].x=x;a[cnt].y=y;
a[cnt].l=i;dui[i]=cnt;
}
if(opt==2)
{
x=read();
a[dui[x]].r=i-1;
}
if(opt==3)
{
x=read();pan[i]=1;
if(x>0) wen[++cnt1].k=x,wen[cnt1].t=i,wen[cnt1].id=i;
else wen1[++cnt2].k=x,wen1[cnt2].t=i,wen1[cnt2].id=i;
}
}
sort(a+1,a+cnt+1,cmp);
sort(wen+1,wen+cnt1+1,cmp1);
sort(wen1+1,wen1+cnt2+1,cmp2);
build(1,1,n);
for(int i=1;i<=cnt;i++) update(1,1,n,a[i].l,a[i].r?a[i].r:n,i);
for(int i=1;i<=cnt1;i++)
{
gudan=-inf;
query(1,1,n,wen[i].t,wen[i].k);
ans[wen[i].id]=gudan;
}
sort(a+1,a+cnt+1,cmp3);
build(1,1,n);
for(int i=1;i<=cnt;i++) update1(1,1,n,a[i].l,a[i].r?a[i].r:n,i);
for(int i=1;i<=cnt2;i++)
{
gudan=-inf;
query1(1,1,n,wen1[i].t,wen1[i].k);
ans[wen1[i].id]=gudan;
}
for(int i=1;i<=n;i++) if(pan[i]) ans[i]==-inf? cout<<"EMPTY SET\n" : cout<<ans[i]<<"\n";
return 0;
}
走上社会,很快会栽跟头
——胡向荣