THUWC2024 题解
t1-小 R 的项目
对于 \(n\) 个子集的 \(2^n\) 个子集,显然只有对这个子集和最大的人有用,所以 \(2^n \times m\) 找出这个人,然后 \(3^n\) 枚举子集合并。
t2-小 R 的序列
先考虑 \(m=1\) 怎么做,因为 \(m\neq 1\) 只需要对上一次的期望做相同的操作就行。
枚举随机到的长度 \(len\),\(i\) 变到的期望是所有包含 \(i\) 的长度为 \(len\) 的区间的和乘 \(\frac{1}{len}\)。
这个不难写成一个矩阵的形式,这样就可以得到 \(n^3 log m\) 的做法。
观察一下发现这个矩阵的每一行都是由上一行移位得到的,所以只需要维护这个矩阵的第一行,这样就可以把矩阵乘法优化到 \(n^2 logm\)。但这是非常显然的卷积形式,使用 NTT 即可做到 \(nlognlogm\)。
t4-小 C 的连廊
将每一行的联通块缩成一个点,相邻的块连一条边,设两个块相交部分 \(y\) 最小的位置的 \(y\) 为 \(y1\),则边权为 \(\min(cnt_{x,y1},cnt_{x+1,y1})\),\(cnt_{i,j}\) 表示对 \((i,j)\) 这个点可以通过的最大风速。这样直接连边的数量是 \(O(q)\) 级别的。然后建立最大生成树,询问 \(x1,y1,x2,y2\) 的答案为 \(cnt_{x1,y1},cnt_{x2,y2}\) 还有这两个点所在联通块的最大生成树上路径上边权的最小值。这样这题就变成了动态维护最大生成树,使用LCT维护。
对第三档分,因为不会相交,所以直接维护 \(n\) 个 set 二分找到有交集的段然后暴力连边,细节不多。
对整道题虽然它会相交,相交的时候会发生变化的边数以及新连接的边数都是 \(O(q)\) 级别的,而且边权都是改大,不会出现一条边之前在生成树上,改之后不在的情况,所以同样直接 set 维护即可,只是细节很多。
代码(不保证是对的,能过小范围对拍与大样例)
#include<bits/stdc++.h>
#define sit set<node>::iterator
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,q,tot;
struct node{
int l,r,id;
node(int l_,int r_,int id_){
l=l_,r=r_,id=id_;
}
bool operator<(const node&x)const{
return l<x.l;
}
};
multiset<node>s[100005];
int w[1000005],X[1000005];
int dy[1000005],o[1000005],up[1000005],down[1000005];
int bel(int x,int y){
sit it=s[x].upper_bound(node(y,0,0));
if(it==s[x].begin())return -1;
it--;
if((*it).r>=y)return (*it).id;
return -1;
}
struct edge{
int x,y,z;
edge(int x_,int y_,int z_){
x=x_,y=y_,z=z_;
}
edge(){}
}e[1000005];
bool inc(int l1,int r1,int l2,int r2){
return max(l1,l2)<=min(r1,r2);
}
struct LCT{
int son[1000005][2],mn[1000005],lazy[1000005],fath[1000005],mnp[1000005];
LCT(){
memset(son,0,sizeof son);
memset(mn,inf,sizeof mn);
memset(lazy,0,sizeof lazy);
memset(fath,0,sizeof fath);
memset(mnp,0,sizeof mnp);
}
int gettype(int x){
return son[fath[x]][1]==x;
}
void rev(int p){
swap(son[p][0],son[p][1]);
}
void pushup(int p){
mn[p]=w[p],mnp[p]=p;
if(mn[son[p][0]]<mn[p]){
mn[p]=mn[son[p][0]];
mnp[p]=mnp[son[p][0]];
}
if(mn[son[p][1]]<mn[p]){
mn[p]=mn[son[p][1]];
mnp[p]=mnp[son[p][1]];
}
}
void pushdown(int p){
if(lazy[p]){
lazy[son[p][0]]^=1,lazy[son[p][1]]^=1;
rev(son[p][0]),rev(son[p][1]);
lazy[p]=0;
}
}
bool isroot(int p){
return son[fath[p]][0]!=p&&son[fath[p]][1]!=p;
}
void rotate(int x){
int y=fath[x],z=fath[y],k=gettype(x);
if(!isroot(y))son[z][gettype(y)]=x;
son[y][k]=son[x][k^1],fath[son[y][k]]=y;
son[x][k^1]=y,fath[y]=x,fath[x]=z;
pushup(y),pushup(x);
}
void pd(int p){
if(!isroot(p))pd(fath[p]);
pushdown(p);
}
void splay(int x){
pd(x);
while(!isroot(x)){
int y=fath[x];
if(!isroot(y)){
if(gettype(x)!=gettype(y))rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x){
for(int s=0;x;s=x,x=fath[x])splay(x),son[x][1]=s,pushup(x);
}
void makeroot(int x){
access(x);
splay(x);
rev(x);
lazy[x]^=1;
}
int findroot(int x){
access(x);
splay(x);
while(son[x][0])x=son[x][0];
splay(x);
return x;
}
void split(int x,int y){
makeroot(x);
access(y);
splay(y);
}
void link(int x,int y){
makeroot(x);
splay(x);
fath[x]=y;
}
void cut(int x,int y){
split(x,y);
fath[x]=0;
son[y][0]=0;
}
int Getmn(int x,int y){
split(x,y);
return mn[y];
}
int Getp(int x,int y){
split(x,y);
return mnp[y];
}
void update(int x,int val){
splay(x);
w[x]=val;
pushup(x);
}
}t;
void addedge(int x,int y,int z){
// cout<<x<<" "<<y<<" "<<z<<endl;
if(t.findroot(x)==t.findroot(y)){
int v=t.Getmn(x,y);
int pos=t.Getp(x,y);
if(v>=z)return;
t.cut(pos,e[pos].x);
t.cut(pos,e[pos].y);
}
tot++;
t.update(tot,z);
t.link(tot,x);
t.link(tot,y);
o[tot]=1;
e[tot]=edge(x,y,z);
}
void merge(int id,int l,int r,int p){
if(l>r)return;
sit it=s[id].lower_bound(node(l,0,0));
if(it!=s[id].begin())it--;
for(;it!=s[id].end();it++){
if((*it).l>r)break;
if(inc((*it).l,(*it).r,l,r)){
int len=min(down[p],(*it).r)-max((*it).l,up[p]);
addedge((*it).id,p,len);
}
}
}
set<node>del;
void upd_lr(int x,int l,int r,int &ll,int &rr){
sit it=s[x].upper_bound(node(l,0,0));
bool tg=0;
if(it!=s[x].begin()){
it--;
tg=1;
}
// cout<<x<<" "<<l<<" "<<r<<":\n";
sit it2=it;if(tg)it2++;
if((l>(*it).r+1||!tg)&&(it2==s[x].end()||r<(*it2).l-1));
else{
if((*it).r>=r&&tg)return;
if((*it).r>=l&&tg);
else{
if(tg){
if((*it).r==l-1)ll=min(ll,(*it).l),rr=max(rr,(*it).r);//,cout<<(*it).l<<" "<<(*it).r<<" 1111\n";
it++;
}
}
for(;;it++){
if(it==s[x].end()||(*it).l>r+1)break;
ll=min(ll,(*it).l);
rr=max(rr,(*it).r);
// cout<<(*it).l<<" "<<(*it).r<<" 3333\n";
}
}
}
int main(){
// system("fc a.out 3.ans /N");
freopen("data.in","r",stdin);
freopen("code.out","w",stdout);
// freopen("3.in","r",stdin);
// freopen("a.out","w",stdout);
scanf("%d%d%d",&q,&n,&m);
while(q--){
int op;
scanf("%d",&op);
if(op==1){
int x,l,r;
scanf("%d%d%d",&x,&l,&r);
tot++;
int llt=tot;
X[llt]=x;
t.update(tot,inf);
if(s[x].empty()){
up[llt]=l,down[llt]=r;
merge(x-1,l,r,llt);
merge(x+1,l,r,llt);
s[x].insert(node(l,r,llt));
continue;
}
sit it=s[x].upper_bound(node(l,0,0));
bool tg=0;
if(it!=s[x].begin()){
it--;
tg=1;
}
// cout<<(it==s[x].end())<<" ";
up[llt]=l,down[llt]=r;
upd_lr(x,l,r,up[llt],down[llt]);
sit it2=it;if(tg)it2++;
if((l>(*it).r+1||!tg)&&(it2==s[x].end()||r<(*it2).l-1)){
// cout<<x<<" "<<l<<" "<<r<<" 1111\n";
merge(x-1,l,r,llt);
merge(x+1,l,r,llt);
}
else{
if((*it).r>=r&&tg)continue;
// cout<<x<<" "<<l<<" "<<r<<" "<<(*it).l<<" "<<(*it).r<<" "<<tg<<":\n";
if((*it).r>=l&&tg){
addedge(llt,(*it).id,inf);
int id=bel(x-1,(*it).r);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
id=bel(x-1,l);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
id=bel(x+1,(*it).r);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
id=bel(x+1,l);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
del.clear();
}
else{
del.clear();
if(tg){
if((*it).r==l-1){
int id=bel(x-1,l);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
id=bel(x+1,l);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
del.insert((*it));
addedge(llt,(*it).id,inf);
}
it++;
}
if(it!=s[x].end()){
int nxt=min((*it).l-1,r);
merge(x-1,l,nxt,llt);
// cout<<l<<" "<<(*it).l-1<<endl;
int id=bel(x-1,nxt);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
id=bel(x-1,l);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
merge(x+1,l,nxt,llt);
id=bel(x+1,nxt);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
id=bel(x+1,l);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
// del.insert((*it));
}
}
for(;;it++){
if(it==s[x].end()||(*it).l>r+1){
it--;
if((*it).r<=r){
// cout<<(*it).r+1<<' '<<r<<endl;
merge(x-1,(*it).r+1,r,llt);
if((*it).r<r){
int id=bel(x-1,(*it).r+1);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
}
merge(x+1,(*it).r+1,r,llt);
int id=bel(x+1,(*it).r+1);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
}
break;
}
sit it1=it;it1++;
if(it1!=s[x].end()&&(*it1).l-1<=r){
merge(x-1,(*it).r+1,(*it1).l-1,llt);
int id=bel(x-1,(*it).r+1);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
id=bel(x-1,(*it1).l-1);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
merge(x+1,(*it).r+1,(*it1).l-1,llt);
id=bel(x+1,(*it).r+1);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
id=bel(x+1,(*it1).l-1);
if(id!=-1)addedge(id,llt,min(down[id],down[llt])-max(up[id],up[llt]));
}
addedge((*it).id,llt,inf);
del.insert((*it));
}
for(auto to:del)s[x].erase(to);
}
s[x].insert(node(up[llt],down[llt],llt));
}
else{
// for(int i=1;i<=tot;i++){
// if(!o[i])
// {
// cout<<X[i]<<" "<<up[i]<<" "<<down[i]<<" "<<i<<endl;
// }
// }
// cout<<endl;
// for(int i=1;i<=n;i++){
// for(auto to:s[i])cout<<i<<" "<<to.l<<" "<<to.r<<" "<<to.id<<endl;
// }
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int p1=bel(x1,y1),p2=bel(x2,y2);
if(p1==-1||p2==-1){
puts("-1");
continue;
}
if(t.findroot(p1)!=t.findroot(p2)){
puts("-1");
continue;
}
int mn1=down[p1]-y1,mn2=down[p2]-y2;
int ans=t.Getmn(p1,p2);
// cout<<mn1<<" "<<mn2<<" "<<ans<<endl;
printf("%d\n",min(min(mn1,mn2),ans));
// return 0;
}
}
return 0;
}