建瓯I栾祚
JOISC2020
[JOISC2020] 収穫
不难看出这个玩意连一下边是个基环树
最开始把树和环分开处理,环上搞个插入删除,整出了个三维偏序
实际上这里直接断一条边,对于环的点就是一样的了
Show Code
#include<bits/stdc++.h>
#define ls Tree[p].lc
#define rs Tree[p].rc
using namespace std;
const int MAXN=2e5+5;
int n,m,L,C;
int a[MAXN*2];
int b[MAXN*2];
int q;
int x;
long long T;
vector<pair<int,int> >g[MAXN];
int tox[MAXN];
int vox[MAXN];
int Rd[MAXN];
long long Lzy[MAXN];
vector<long long>S[MAXN];
int Lorp[MAXN];
int cnt_lorp;
int vis[MAXN];
vector<pair<int,long long> >Qry[MAXN];
long long Ans[MAXN];
void find(int x)
{
if(vis[x])
{
return;
}
vis[x]=1;
Lorp[++cnt_lorp]=x;
find(tox[x]);
}
long long dep[MAXN];
struct Seg_node{
int lc,rc;
int date;
};
struct Seg{
Seg_node Tree[MAXN*40];
int rt;
int cnt_node;
int New()
{
int p=++cnt_node;
Tree[p].date=0;
Tree[p].lc=Tree[p].rc=0;
return p;
}
void Insert(int &p,long long l,long long r,long long x,int k)
{
if(!p)
{
p=New();
}
Tree[p].date+=k;
if(l==r)
{
return;
}
long long mid=(l+r)>>1;
if(x<=mid)
{
Insert(ls,l,mid,x,k);
}
else
{
Insert(rs,mid+1,r,x,k);
}
}
int Query(int p,long long l,long long r,long long ql,long long qr)
{
if(ql>qr)
{
return 0;
}
if(!p)
{
return 0;
}
if(l>=ql&&r<=qr)
{
return Tree[p].date;
}
long long mid=(l+r)>>1;
int Res=0;
if(ql<=mid)
{
Res+=Query(ls,l,mid,ql,qr);
}
if(qr>mid)
{
Res+=Query(rs,mid+1,r,ql,qr);
}
return Res;
}
int Merge(int x,int y,long long l,long long r)
{
if((!x)||(!y))
{
return x+y;
}
Tree[x].date+=Tree[y].date;
if(l==r)
{
return x;
}
long long mid=(l+r)>>1;
Tree[x].lc=Merge(Tree[x].lc,Tree[y].lc,l,mid);
Tree[x].rc=Merge(Tree[x].rc,Tree[y].rc,mid+1,r);
return x;
}
}t,t1;
int rt[MAXN];
void dfs(int x,int fob)
{
//cerr<<x<<endl;
for(int i=0;i<S[x].size();i++)
{
S[x][i]+=dep[x];
t.Insert(rt[x],0,2e14,S[x][i],1);
}
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i].first;
int w=g[x][i].second;
if(v==fob)
{
continue;
}
dep[v]=dep[x]+w;
dfs(v,fob);
rt[x]=t.Merge(rt[x],rt[v],0,2e14);
if(S[v].size()>S[x].size())
{
swap(S[x],S[v]);
}
for(int j=0;j<S[v].size();j++)
{
S[x].push_back(S[v][j]);
}
}
for(int i=0;i<Qry[x].size();i++)
{
int id=Qry[x][i].first;
long long T=Qry[x][i].second+dep[x];
Ans[id]+=t.Query(rt[x],0,2e14,0,T);
}
}
long long sm[MAXN];
long long Chu(long long x,long long k)
{
if(x>0)
{
return x/k;
}
else
{
return (x-(x%k+k)%k)/k;
}
}
long long Mod(long long x,long long k)
{
return ((x%k)+k)%k;
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d %d %d",&n,&m,&L,&C);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%d",&b[i]);
}
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%d %lld",&x,&T);
Qry[x].push_back(make_pair(i,T));
}
for(int i=1;i<=n;i++)
{
a[i+n]=a[i]+L;
}
for(int i=1;i<=m;i++)
{
b[i]+=L;
}
vector<pair<int,int> >V;
for(int i=1;i<=2*n;i++)
{
V.push_back(make_pair(a[i],i));
}
for(int i=1;i<=m;i++)
{
V.push_back(make_pair(b[i],2*n+1));
}
sort(V.begin(),V.end());
int Nid=-1;
for(int i=0;i<V.size();i++)
{
if(V[i].second<=2*n)
{
Nid=V[i].second;
}
else
{
int pid=Nid;
if(pid>n)
{
pid-=n;
}
//cerr<<pid<<" "<<V[i].first-a[Nid]<<endl;
S[pid].push_back(V[i].first-a[Nid]);
}
}
for(int i=1;i<=n;i++)
{
int Copx=(C/L);
int Rwi=C%L;
int l=1;
int r=i+n;
int Key;
while(l<=r)
{
int mid=(l+r)>>1;
if(a[n+i]-a[mid]>=Rwi)
{
Key=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
int D=a[n+i]-a[Key];
if(Key>n)
{
Key-=n;
}
g[Key].push_back(make_pair(i,D+Copx*L));
tox[i]=Key;
vox[i]=D+Copx*L;
Rd[Key]++;
//cerr<<tox[i]<<" "<<vox[i]<<endl;
}
queue<int>Q;
for(int i=1;i<=n;i++)
{
if(!Rd[i])
{
Q.push(i);
}
}
while(Q.size())
{
int tmp=Q.front();
Q.pop();
Rd[tox[tmp]]--;
if(!Rd[tox[tmp]])
{
Q.push(tox[tmp]);
}
}
for(int ie=1;ie<=n;ie++)
{
if(Rd[ie]&&(!vis[ie]))
{
cnt_lorp=0;
find(ie);
long long wL=0;
for(int i=1;i<=cnt_lorp;i++)
{
sm[i]=wL;
wL+=vox[Lorp[i]];
}
sm[1]=wL;
t.cnt_node=0;
t.rt=0;
dfs(Lorp[1],Lorp[1]);
//cerr<<wL<<endl;
vector<pair<long long,int> >Qst;
for(int i=1;i<=cnt_lorp;i++)
{
for(int j=0;j<Qry[Lorp[i]].size();j++)
{
Qst.push_back(make_pair(Qry[Lorp[i]][j].second-sm[i],Qry[Lorp[i]][j].first));
}
}
for(int i=0;i<S[Lorp[1]].size();i++)
{
Qst.push_back(make_pair(S[Lorp[1]][i],0));
}
sort(Qst.begin(),Qst.end());
t1.cnt_node=0;
t1.rt=0;
long long Suw=0;
int DJWWWW=0;
//cerr<<Ans[1]<<endl;
for(int i=0;i<Qst.size();i++)
{
//printf("%lld %lld\n",Qst[i].first,Qst[i].second);
if(Qst[i].second==0)
{
t1.Insert(t1.rt,0,2e14,Mod(Qst[i].first,wL),1);
Suw+=Chu(Qst[i].first,wL);
DJWWWW++;
}
else
{
int id=Qst[i].second;
long long Res=Chu(Qst[i].first,wL)*DJWWWW;
Res-=Suw;
Res-=t1.Query(t1.rt,0,2e14,Mod(Qst[i].first,wL)+1,2e14);
Res+=DJWWWW;
Ans[id]+=Res;
}
}
//cerr<<Lorp[1]<<endl;
}
}
for(int i=1;i<=q;i++)
{
printf("%lld\n",Ans[i]);
}
}
[JOISC2020] 美味しい美味しいハンバーグ
有点被恶心到了
\(k\le 3\)的,直接考虑最左右边界\(L\),最右左边界\(R\)还有\(U,D\)构成的矩形\(M\)
构不成的很好构造
四条边界是一定要选的,因此一定要选顶点,递归即可
\(k=4\),可能在四条边界
不过我们可以发现一个矩形只会和\(M\)有\(1/2\)条边相交
用前缀的思想跑\(2-SAT\)即可
Show Code
#include<bits/stdc++.h>
#define x1 jjrx
#define y1 keke
#define x2 ewewe
#define y2 jrjrjrj
using namespace std;
const int MAXN=4e5+5;
struct Martix{
int x1,y1,x2,y2;
}a[MAXN],b[MAXN];
bool In(Martix p,int x,int y)
{
if(x>=p.x1&&x<=p.x2&&y>=p.y1&&y<=p.y2)
{
return 1;
}
return 0;
}
bool cmpx(Martix x,Martix y)
{
if(x.x1==y.x1)
{
return x.x2>y.x2;
}
return x.x1<y.x1;
}
bool cmpy(Martix x,Martix y)
{
if(x.y1==y.y1)
{
return x.y2>y.y2;
}
return x.y1<y.y1;
}
vector<pair<int,int> >Used;
void dfs(vector<Martix> V,int k)
{
if(!V.size())
{
for(int i=0;i<Used.size();i++)
{
printf("%d %d\n",Used[i].first,Used[i].second);
}
while(k--)
{
printf("1 1\n");
}
exit(0);
}
if(!k)
{
return;
}
int Lx=1e9+1,Rx=0,Ly=1e9+1,Ry=0;
for(int i=0;i<V.size();i++)
{
//scanf("%d %d %d %d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
Lx=min(Lx,V[i].x2);
Ly=min(Ly,V[i].y2);
Rx=max(Rx,V[i].x1);
Ry=max(Ry,V[i].y1);
}
Used.push_back(make_pair(Lx,Ly));
vector<Martix>Kw;
for(int i=0;i<V.size();i++)
{
if(In(V[i],Lx,Ly))
{
}
else
{
Kw.push_back(V[i]);
}
}
dfs(Kw,k-1);
Used.pop_back();
Kw.clear();
Used.push_back(make_pair(Lx,Ry));
for(int i=0;i<V.size();i++)
{
if(In(V[i],Lx,Ry))
{
}
else
{
Kw.push_back(V[i]);
}
}
dfs(Kw,k-1);
Used.pop_back();
Kw.clear();
Used.push_back(make_pair(Rx,Ry));
for(int i=0;i<V.size();i++)
{
if(In(V[i],Rx,Ry))
{
}
else
{
Kw.push_back(V[i]);
}
}
dfs(Kw,k-1);
Used.pop_back();
Kw.clear();
Used.push_back(make_pair(Rx,Ly));
for(int i=0;i<V.size();i++)
{
if(In(V[i],Rx,Ly))
{
}
else
{
Kw.push_back(V[i]);
}
}
dfs(Kw,k-1);
Used.pop_back();
}
int n,k;
int lshx[MAXN];
int lshy[MAXN];
int cnt_lshx;
int cnt_lshy;
vector<int>g[MAXN*8];
int Id[MAXN][2][2][2];
int Cnt=0;
void Get(int id,int op1,int op2,int l,int r)
{
//cerr<<"fci"<<endl;
g[id].push_back(Id[r][op1][op2][1]);
assert(id);
Cnt++;
if(Id[l-1][op1][op2][0])
{
g[id].push_back(Id[l-1][op1][op2][0]);
assert(id);
Cnt++;
}
}
int dfn[MAXN*8];
int cnt_dfn;
int low[MAXN*8];
int cnt_scc;
stack<int>st;
int scc[MAXN*8];
void find(int x)
{
st.push(x);
dfn[x]=++cnt_dfn;
low[x]=dfn[x];
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(dfn[v])
{
if(!scc[v])
{
low[x]=min(low[x],dfn[v]);
}
}
else
{
find(v);
low[x]=min(low[x],low[v]);
}
}
if(dfn[x]==low[x])
{
++cnt_scc;
while(st.size())
{
scc[st.top()]=cnt_scc;
if(st.top()==x)
{
st.pop();
break;
}
st.pop();
}
}
}
int main()
{
//#ifdef LOCAL
// freopen("date.in", "r", stdin);
// freopen("date.out", "w", stdout);
// #endif
scanf("%d %d",&n,&k);
int Lx=1e9+1,Rx=0,Ly=1e9+1,Ry=0;
for(int i=1;i<=n;i++)
{
scanf("%d %d %d %d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
Lx=min(Lx,a[i].x2);
Ly=min(Ly,a[i].y2);
Rx=max(Rx,a[i].x1);
Ry=max(Ry,a[i].y1);
}
if(Lx>=Rx&&Ly>=Ry)
{
while(k--)
{
printf("%d %d\n",Lx,Ly);
}
}
else if(Lx>=Rx||Ly>=Ry)
{
if(Lx>=Rx)
{
sort(a+1,a+1+n,cmpy);
int m=0;
b[++m]=a[1];
for(int i=2;i<=n;i++)
{
while(m&&a[i].y2<=b[m].y2)
{
m--;
}
b[++m]=a[i];
}
n=m;
for(int i=1;i<=n;i++)
{
a[i]=b[i];
}
int R=0;
for(int i=1;i<=n;i++)
{
if(a[i].y1>R)
{
printf("%d %d\n",Lx,a[i].y2);
R=a[i].y2;
k--;
}
}
while(k--)
{
printf("1 1\n");
}
}
else
{
sort(a+1,a+1+n,cmpx);
int m=0;
b[++m]=a[1];
for(int i=2;i<=n;i++)
{
while(m&&a[i].x2<=b[m].x2)
{
m--;
}
b[++m]=a[i];
}
n=m;
for(int i=1;i<=n;i++)
{
a[i]=b[i];
}
int R=0;
for(int i=1;i<=n;i++)
{
if(a[i].x1>R)
{
printf("%d %d\n",a[i].x2,Ly);
R=a[i].x2;
k--;
}
}
while(k--)
{
printf("1 1\n");
}
}
}
else
{
// cerr<<"fc"<<endl;
vector<Martix>V;
for(int i=1;i<=n;i++)
{
V.push_back(a[i]);
}
dfs(V,k);
for(int i=1;i<=n;i++)
{
lshx[++cnt_lshx]=a[i].x1;
lshx[++cnt_lshx]=a[i].x2;
lshy[++cnt_lshy]=a[i].y1;
lshy[++cnt_lshy]=a[i].y2;
}
sort(lshx+1,lshx+1+cnt_lshx);
cnt_lshx=unique(lshx+1,lshx+1+cnt_lshx)-lshx-1;
sort(lshy+1,lshy+1+cnt_lshy);
cnt_lshy=unique(lshy+1,lshy+1+cnt_lshy)-lshy-1;
for(int i=1;i<=n;i++)
{
a[i].x1=lower_bound(lshx+1,lshx+1+cnt_lshx,a[i].x1)-lshx;
a[i].x2=lower_bound(lshx+1,lshx+1+cnt_lshx,a[i].x2)-lshx;
a[i].y1=lower_bound(lshy+1,lshy+1+cnt_lshy,a[i].y1)-lshy;
a[i].y2=lower_bound(lshy+1,lshy+1+cnt_lshy,a[i].y2)-lshy;
}
Lx=lower_bound(lshx+1,lshx+1+cnt_lshx,Lx)-lshx;
Rx=lower_bound(lshx+1,lshx+1+cnt_lshx,Rx)-lshx;
Ly=lower_bound(lshy+1,lshy+1+cnt_lshy,Ly)-lshy;
Ry=lower_bound(lshy+1,lshy+1+cnt_lshy,Ry)-lshy;
int cnt_node=0;
for(int i=1;i<=cnt_lshx;i++)
{
Id[i][0][0][0]=++cnt_node;
Id[i][0][0][1]=++cnt_node;
Id[i][0][1][0]=++cnt_node;
Id[i][0][1][1]=++cnt_node;
if(i>1)
{
g[Id[i-1][0][0][1]].push_back(Id[i][0][0][1]);
g[Id[i][0][0][0]].push_back(Id[i-1][0][0][0]);
g[Id[i-1][0][1][1]].push_back(Id[i][0][1][1]);
g[Id[i][0][1][0]].push_back(Id[i-1][0][1][0]);
Cnt+=4;
}
}
for(int i=1;i<=cnt_lshy;i++)
{
Id[i][1][0][0]=++cnt_node;
Id[i][1][0][1]=++cnt_node;
Id[i][1][1][0]=++cnt_node;
Id[i][1][1][1]=++cnt_node;
if(i>1)
{
g[Id[i-1][1][0][1]].push_back(Id[i][1][0][1]);
g[Id[i][1][0][0]].push_back(Id[i-1][1][0][0]);
g[Id[i-1][1][1][1]].push_back(Id[i][1][1][1]);
g[Id[i][1][1][0]].push_back(Id[i-1][1][1][0]);
Cnt+=4;
}
}
g[Id[Rx][0][0][0]].push_back(Id[Rx][0][0][1]);
g[Id[Rx][0][1][0]].push_back(Id[Rx][0][1][1]);
g[Id[Ry][1][0][0]].push_back(Id[Ry][1][0][1]);
g[Id[Ry][1][1][0]].push_back(Id[Ry][1][1][1]);
Cnt+=4;
if(Lx>1)
{
g[Id[Lx-1][0][0][1]].push_back(Id[Lx-1][0][0][0]);
g[Id[Lx-1][0][1][1]].push_back(Id[Lx-1][0][1][0]);
g[Id[Ly-1][1][0][1]].push_back(Id[Ly-1][1][0][0]);
g[Id[Ly-1][1][1][1]].push_back(Id[Ly-1][1][1][0]);
Cnt+=4;
}
cerr<<cnt_node<<endl;
cerr<<Cnt<<endl;
for(int i=1;i<=n;i++)
{
if(a[i].x1<=Lx&&a[i].x2>=Rx&&(Ly>=a[i].y1&&Ly<=a[i].y2))
{
continue;
}
if(a[i].x1<=Lx&&a[i].x2>=Rx&&(Ry>=a[i].y1&&Ry<=a[i].y2))
{
continue;
}
if(a[i].y1<=Ly&&a[i].y2>=Ry&&(Lx>=a[i].x1&&Lx<=a[i].x2))
{
continue;
}
if(a[i].y1<=Ly&&a[i].y2>=Ry&&(Rx>=a[i].x1&&Rx<=a[i].x2))
{
continue;
}
if(a[i].x1>=Lx&&a[i].x2<=Rx)
{
if((Ly>=a[i].y1&&Ly<=a[i].y2)&&(Ry>=a[i].y1&&Ry<=a[i].y2))
{
Get(Id[a[i].x2][0][0][0],0,1,a[i].x1,a[i].x2);
Get(Id[a[i].x2][0][1][0],0,0,a[i].x1,a[i].x2);
if(Id[a[i].x1-1][0][0][1])
{
Get(Id[a[i].x1-1][0][0][1],0,1,a[i].x1,a[i].x2);
Get(Id[a[i].x1-1][0][1][1],0,0,a[i].x1,a[i].x2);
}
}
else if((Ly>=a[i].y1&&Ly<=a[i].y2))
{
//cerr<<"fucj"<<endl;
if(Id[a[i].x1-1][0][0][1])
{
//cerr<<"iidu"<<endl;
g[Id[a[i].x1-1][0][0][1]].push_back(Id[a[i].x1-1][0][0][0]);
Cnt++;
}
g[Id[a[i].x2][0][0][0]].push_back(Id[a[i].x2][0][0][1]);
Cnt++;
}
else if((Ry>=a[i].y1&&Ry<=a[i].y2))
{
if(Id[a[i].x1-1][0][1][1])
{
g[Id[a[i].x1-1][0][1][1]].push_back(Id[a[i].x1-1][0][1][0]);
Cnt++;
}
g[Id[a[i].x2][0][1][0]].push_back(Id[a[i].x2][0][1][1]);
Cnt++;
}
else
{
assert(0);
}
}
else if(a[i].y1>=Ly&&a[i].y2<=Ry)
{
if((Lx>=a[i].x1&&Lx<=a[i].x2)&&(Rx>=a[i].x1&&Rx<=a[i].x2))
{
Get(Id[a[i].y2][1][0][0],1,1,a[i].y1,a[i].y2);
Get(Id[a[i].y2][1][1][0],1,0,a[i].y1,a[i].y2);
if(Id[a[i].y1-1][1][0][1])
{
Get(Id[a[i].y1-1][1][0][1],1,1,a[i].y1,a[i].y2);
Get(Id[a[i].y1-1][1][1][1],1,0,a[i].y1,a[i].y2);
}
}
else if((Lx>=a[i].x1&&Lx<=a[i].x2))
{
if(Id[a[i].y1-1][1][0][1])
{
g[Id[a[i].y1-1][1][0][1]].push_back(Id[a[i].y1-1][1][0][0]);
Cnt++;
}
g[Id[a[i].y2][1][0][0]].push_back(Id[a[i].y2][1][0][1]);
Cnt++;
}
else if((Rx>=a[i].x1&&Rx<=a[i].x2))
{
if(Id[a[i].y1-1][1][1][1])
{
g[Id[a[i].y1-1][1][1][1]].push_back(Id[a[i].y1-1][1][1][0]);
Cnt++;
}
g[Id[a[i].y2][1][1][0]].push_back(Id[a[i].y2][1][1][1]);
Cnt++;
}
else
{
assert(0);
}
}
else
{
if(a[i].x2>=Lx&&a[i].x2<=Rx)
{
if(a[i].y2>=Ly&&a[i].y2<=Ry)
{
g[Id[a[i].x2][0][0][0]].push_back(Id[a[i].y2][1][0][1]);
g[Id[a[i].y2][1][0][0]].push_back(Id[a[i].x2][0][0][1]);
Cnt+=2;
}
else
{
if(Id[a[i].y1-1][1][0][0])
{
g[Id[a[i].x2][0][1][0]].push_back(Id[a[i].y1-1][1][0][0]);
Cnt++;
}
if(Id[a[i].y1-1][1][0][1])
{
g[Id[a[i].y1-1][1][0][1]].push_back(Id[a[i].x2][0][1][1]);
Cnt++;
}
}
}
else
{
if(a[i].y2>=Ly&&a[i].y2<=Ry)
{
if(Id[a[i].x1-1][0][0][1])
{
g[Id[a[i].x1-1][0][0][1]].push_back(Id[a[i].y2][1][1][1]);
Cnt++;
}
if(Id[a[i].x1-1][0][0][0])
{
g[Id[a[i].y2][1][1][0]].push_back(Id[a[i].x1-1][0][0][0]);
Cnt++;
}
}
else
{
if(Id[a[i].x1-1][0][1][1]&&Id[a[i].y1-1][1][1][0])
{
g[Id[a[i].x1-1][0][1][1]].push_back(Id[a[i].y1-1][1][1][0]);
Cnt++;
}
if(Id[a[i].y1-1][1][1][1]&&Id[a[i].x1-1][0][1][0])
{
g[Id[a[i].y1-1][1][1][1]].push_back(Id[a[i].x1-1][0][1][0]);
Cnt++;
}
}
}
}
}
cerr<<cnt_lshx<<" "<<cnt_lshy<<endl;
int tot=0;
for(int i=0;i<=cnt_node;i++)
{
tot+=g[i].size();
}
cerr<<Cnt<<endl;
cerr<<tot<<endl;
for(int i=1;i<=cnt_node;i++)
{
if(!dfn[i])
{
find(i);
}
}
int Kx=Rx;
for(int i=Lx;i<=Rx;i++)
{
//cerr<<scc[Id[i][0][0][0]]<<" "<<scc[Id[i][0][0][1]]<<endl;
if(scc[Id[i][0][0][0]]==scc[Id[i][0][0][1]])
{
assert(0);
}
if(scc[Id[i][0][0][1]]<scc[Id[i][0][0][0]])
{
Kx=i;
break;
}
}
printf("%d %d\n",lshx[Kx],lshy[Ly]);
Kx=Rx;
for(int i=Lx;i<=Rx;i++)
{
if(scc[Id[i][0][1][0]]==scc[Id[i][0][1][1]])
{
assert(0);
}
if(scc[Id[i][0][1][1]]<scc[Id[i][0][1][0]])
{
Kx=i;
break;
}
}
printf("%d %d\n",lshx[Kx],lshy[Ry]);
int Ky=Ry;
for(int i=Ly;i<=Ry;i++)
{
if(scc[Id[i][1][0][0]]==scc[Id[i][1][0][1]])
{
assert(0);
}
if(scc[Id[i][1][0][1]]<scc[Id[i][1][0][0]])
{
Ky=i;
break;
}
}
printf("%d %d\n",lshx[Lx],lshy[Ky]);
Ky=Ry;
for(int i=Ly;i<=Ry;i++)
{
if(scc[Id[i][1][1][0]]==scc[Id[i][1][1][1]])
{
assert(0);
}
if(scc[Id[i][1][1][1]]<scc[Id[i][1][1][0]])
{
Ky=i;
break;
}
}
printf("%d %d\n",lshx[Rx],lshy[Ky]);
}
}
[JOISC2020] 掃除
部分分很有提示性
考虑当前所有灰尘都被操作过了
那么现在灰尘大概长成折线的样子
后续操作不管怎么做都不会改变相对顺序
我们可以直接求出每个灰尘第一次被操作的时间然后插进平衡树里
不过难办的是如果新添加一个灰尘,它在经过若干次操作后不一定会达到折线的位置
考虑用类似线段树分治的结构,处理\([l,r]\)的操作时将能被处理的灰尘提前加进去,并将结果作为新状态
这样就能保证每次处理都不会新填灰尘
Show Code
#include<bits/stdc++.h>
#define ls Tree[p].lc
#define rs Tree[p].rc
using namespace std;
const int MAXN=1.5e6+5;
mt19937 Niuzida(998244353);
struct node{
int x,y;
bool operator<(const node p)const{
if(x==p.x)
{
return y>p.y;
}
return x<p.x;
}
bool operator<=(const node p)const{
if(x==p.x)
{
return y>=p.y;
}
return x<p.x;
}
}A[MAXN];
struct FHQ_node{
int lc,rc;
node val;
int lzyx;
int lzyy;
int Key;
};
struct FHQ{
int rt;
int cnt_node;
FHQ_node Tree[MAXN];
int New(int x,int y)
{
++cnt_node;
Tree[cnt_node].lc=Tree[cnt_node].rc=0;
Tree[cnt_node].lzyx=Tree[cnt_node].lzyy=-1;
Tree[cnt_node].Key=(Niuzida());
Tree[cnt_node].val=(node){x,y};
return cnt_node;
}
void push_down(int p)
{
if(Tree[p].lzyx!=-1)
{
if(ls)
{
Tree[ls].lzyx=max(Tree[ls].lzyx,Tree[p].lzyx);
Tree[ls].val.x=max(Tree[ls].val.x,Tree[p].lzyx);
}
if(rs)
{
Tree[rs].lzyx=max(Tree[rs].lzyx,Tree[p].lzyx);
Tree[rs].val.x=max(Tree[rs].val.x,Tree[p].lzyx);
}
Tree[p].lzyx=-1;
}
if(Tree[p].lzyy!=-1)
{
if(ls)
{
Tree[ls].lzyy=max(Tree[ls].lzyy,Tree[p].lzyy);
Tree[ls].val.y=max(Tree[ls].val.y,Tree[p].lzyy);
}
if(rs)
{
Tree[rs].lzyy=max(Tree[rs].lzyy,Tree[p].lzyy);
Tree[rs].val.y=max(Tree[rs].val.y,Tree[p].lzyy);
}
Tree[p].lzyy=-1;
}
}
void Split(int p,int &x,int &y,node k)
{
if(!p)
{
x=y=0;
return;
}
push_down(p);
if(Tree[p].val<=k)
{
x=p;
Split(rs,rs,y,k);
}
else
{
y=p;
Split(ls,x,ls,k);
}
}
void Splitx(int p,int &x,int &y,int k)
{
if(!p)
{
x=y=0;
return;
}
push_down(p);
if(Tree[p].val.x<=k)
{
x=p;
Splitx(rs,rs,y,k);
}
else
{
y=p;
Splitx(ls,x,ls,k);
}
}
void Splity(int p,int &x,int &y,int k)
{
if(!p)
{
x=y=0;
return;
}
push_down(p);
if(Tree[p].val.y>=k)
{
x=p;
Splity(rs,rs,y,k);
}
else
{
y=p;
Splity(ls,x,ls,k);
}
}
int Merge(int x,int y){
if((!x)||(!y))
{
return x+y;
}
if(Tree[x].Key<Tree[y].Key)
{
push_down(x);
Tree[x].rc=Merge(Tree[x].rc,y);
return x;
}
else
{
push_down(y);
Tree[y].lc=Merge(x,Tree[y].lc);
return y;
}
}
void Put(int p)
{
if(!p)
{
return;
}
push_down(p);
Put(ls);
Put(rs);
}
}t1;
struct Seg_node{
int lc,rc;
int date;
};
struct Segg{
Seg_node Tree[MAXN*8];
int rt;
int cnt_node;
void Insert(int &p,int l,int r,int k,int x)
{
if(!p)
{
p=++cnt_node;
Tree[p].lc=Tree[p].rc=0;
Tree[p].date=1e9;
}
Tree[p].date=min(Tree[p].date,x);
if(l==r)
{
return;
}
int mid=(l+r)>>1;
if(k<=mid)
{
Insert(ls,l,mid,k,x);
}
else
{
Insert(rs,mid+1,r,k,x);
}
}
int Query(int p,int l,int r,int ql,int qr)
{
if(!p)
{
return 1e9;
}
if(l>=ql&&r<=qr)
{
return Tree[p].date;
}
int mid=(l+r)>>1;
int Res=1e9;
if(ql<=mid)
{
Res=min(Res,Query(ls,l,mid,ql,qr));
}
if(qr>mid)
{
Res=min(Res,Query(rs,mid+1,r,ql,qr));
}
return Res;
}
}t2;
int n,m,q;
int Cnt=0;
int Fix[MAXN];
struct Query{
int op;
node p;
int l;
}Qry[MAXN];
int x,y;
int op;
int Ans[MAXN];
struct Seg{
vector<int>Rec;
int lc,rc;
}Tree[MAXN*4];
int rt;
int cnt_node;
void Insert(int &p,int l,int r,int ql,int qr,int id)
{
if(!p)
{
p=++cnt_node;
Tree[p].lc=Tree[p].rc=0;
Tree[p].Rec.clear();
}
//cerr<<ql<<" "<<qr<<endl;
if(l>=ql&&r<=qr)
{
Tree[p].Rec.push_back(id);
return;
}
int mid=(l+r)>>1;
if(ql<=mid)
{
Insert(ls,l,mid,ql,qr,id);
}
if(qr>mid)
{
Insert(rs,mid+1,r,ql,qr,id);
}
}
vector<int>Ioa[MAXN];
int Rlf[MAXN];
void solve(int p,int l,int r)
{
if(!p)
{
return;
}
t1.rt=t1.cnt_node=0;
t2.rt=t2.cnt_node=0;
for(int i=l;i<=r;i++)
{
if(Qry[i].op==2)
{
t2.Insert(t2.rt,0,n,n-Qry[i].l,i);
}
else if(Qry[i].op==3)
{
t2.Insert(t2.rt,0,n,Qry[i].l,i);
}
Ioa[i].clear();
}
// if(l==7&&r==7)
// {
// printf("%dzwuzwuuzuwuuuuzuu\n",t2.rt);
// }
for(int i=0;i<Tree[p].Rec.size();i++)
{
int id=Tree[p].Rec[i];
int Tim=t2.Query(t2.rt,0,n,Qry[id].p.x,n-Qry[id].p.y);
//printf("%d??\n",Tim);
// cerr<<Tim<<endl;
// cerr<<Qry[id].p.x<<" "<<n-Qry[id].p.y<<endl;
if(Tim<=r)
{
Ioa[Tim].push_back(id);
}
}
for(int i=l;i<=r;i++)
{
if(Qry[i].op==2)
{
int lx,rx;
t1.Splity(t1.rt,lx,rx,Qry[i].l+1);
//printf("%d %d %d??\n",rx,t1.Tree[rx].val.x,t1.Tree[rx].val.y);
if(rx)
{
t1.Tree[rx].val.x=max(t1.Tree[rx].val.x,n-Qry[i].l);
t1.Tree[rx].lzyx=max(t1.Tree[rx].lzyx,n-Qry[i].l);
//printf("%d %d %d %d??\n",rx,t1.Tree[rx].val.x,t1.Tree[rx].val.y,Qry[i].l);
}
t1.rt=t1.Merge(lx,rx);
for(int j=0;j<Ioa[i].size();j++)
{
int id=Ioa[i][j];
Qry[id].p.x=max(Qry[id].p.x,n-Qry[i].l);
int lx,rx;
t1.Split(t1.rt,lx,rx,Qry[id].p);
int zx=t1.New(Qry[id].p.x,Qry[id].p.y);
Rlf[id]=zx;
t1.rt=t1.Merge(lx,t1.Merge(zx,rx));
//printf("%d %d??\n",Qry[id].p.x,Qry[id].p.y);
}
}
else if(Qry[i].op==3)
{
int lx,rx;
t1.Splitx(t1.rt,lx,rx,Qry[i].l);
if(lx)
{
t1.Tree[lx].val.y=max(t1.Tree[lx].val.y,n-Qry[i].l);
t1.Tree[lx].lzyy=max(t1.Tree[lx].lzyy,n-Qry[i].l);
}
t1.rt=t1.Merge(lx,rx);
for(int j=0;j<Ioa[i].size();j++)
{
int id=Ioa[i][j];
Qry[id].p.y=max(Qry[id].p.y,n-Qry[i].l);
int lx,rx;
t1.Split(t1.rt,lx,rx,Qry[id].p);
//printf("%d %d??????\n",Qry[id].p.x,Qry[id].p.y);
int zx=t1.New(Qry[id].p.x,Qry[id].p.y);
Rlf[id]=zx;
t1.rt=t1.Merge(lx,t1.Merge(zx,rx));
}
}
}
t1.Put(t1.rt);
//printf("%d %d::\n",l,r);
for(int i=0;i<Tree[p].Rec.size();i++)
{
int id=Tree[p].Rec[i];
int Tim=t2.Query(t2.rt,0,n,Qry[id].p.x,n-Qry[id].p.y);
if(Tim<=r)
{
//cerr<<t1.Tree[Rlf[id]].val.x<<endl;
Qry[id].p=t1.Tree[Rlf[id]].val;
}
// printf("%d %d %d %d?\n",id,Qry[id].p.x,Qry[id].p.y,Tim);
}
//printf("%d %dfuckfuckfuckfuckfuckf\n",Qry[7].p.x,Qry[7].p.y);
if(l==r)
{
return;
}
int mid=(l+r)>>1;
solve(ls,l,mid);
solve(rs,mid+1,r);
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
A[++Cnt]=((node){x,y});
Fix[i]=0;
}
for(int i=1;i<=q;i++)
{
scanf("%d",&op);
Qry[i].op=op;
if(op==1)
{
scanf("%d",&x);
Qry[i].p=A[x];
Insert(rt,1,q,Fix[x]+1,i,i);
}
else if(op==2)
{
scanf("%d",&x);
Qry[i].l=x;
}
else if(op==3)
{
scanf("%d",&x);
Qry[i].l=x;
}
else
{
scanf("%d %d",&x,&y);
A[++Cnt]=(node){x,y};
Fix[Cnt]=i;
}
}
solve(1,1,q);
for(int i=1;i<=q;i++)
{
if(Qry[i].op==1)
{
printf("%d %d\n",Qry[i].p.x,Qry[i].p.y);
}
}
}
[JOISC2020] ジョイッターで友だちをつくろう
一个思路简单不好实现的题
大体上我们把合并后的有向边重新再跑一次
这样似乎好写一点(orz DJ!!!!)
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
int n,m;
int x,y;
int fa[MAXN];
int find(int x)
{
if(fa[x]==x)
{
return fa[x];
}
fa[x]=find(fa[x]);
return fa[x];
}//
set<int>In[MAXN],Out[MAXN],Opx[MAXN],Ipx[MAXN];
vector<int>R[MAXN];
long long Res=0;
int Vis[MAXN];
deque<pair<int,int > >Q;
void unionn(int x,int y)
{
int ex=find(x);
int ey=find(y);
if(ex==ey)
{
return;
}
//printf("%d %d::\n",x,y);
if(Opx[x].find(find(y))!=Opx[x].end())
{
return;
}
if(In[ex].find(ey)==In[ex].end())
{
// printf("%d %d::\n",x,y);
Res+=(int)R[ey].size();
Out[ex].insert(ey);
In[ey].insert(ex);
Opx[x].insert(ey);
Ipx[ey].insert(x);
return;
}
else
{
//cerr<<"woxs"<<endl;
//printf("%d %d??\n",x,y);
Res-=((int)R[ex].size()*(R[ex].size()-1));
Res-=((int)R[ey].size()*(R[ey].size()-1));
//cerr<<R[ex].size()<<endl;
//cerr<<R[ey].size()<<endl;
In[ex].erase(ey);
Out[ey].erase(ex);
if(R[ex].size()>R[ey].size())
{
swap(ex,ey);
}
for(int i=0;i<R[ex].size();i++)
{
int id=R[ex][i];
vector<int>Wix;
for(auto iap=Opx[id].begin();iap!=Opx[id].end();iap++)
{
Wix.push_back((*iap));
}
for(int j=0;j<Wix.size();j++)
{
int v=Wix[j];
v=find(v);
Res-=R[v].size();
Ipx[v].erase(id);
Opx[id].erase(v);
Q.push_back(make_pair(id,v));
}
}
for(auto it=Ipx[ex].begin();it!=Ipx[ex].end();it++)
{
int id=(*it);
Res-=R[ex].size();
Opx[id].erase(ex);
Q.push_back(make_pair(id,ex));
}
Ipx[ex].clear();
for(int i=0;i<R[ex].size();i++)
{
R[ey].push_back(R[ex][i]);
}
Res+=((int)R[ey].size()*(R[ey].size()-1));
Res+=((int)R[ex].size()*Ipx[ey].size());
fa[ex]=ey;
// cerr<<R[ey].size()<<endl;
}
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
fa[i]=i;
R[i].push_back(i);
}
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
Q.push_back(make_pair(x,y));
while(Q.size())
{
auto tmp=Q.front();
Q.pop_front();
unionn(tmp.first,tmp.second);
}
printf("%lld\n",Res);
}
}
[JOISC2020] カメレオンの恋
一个奇怪的东西
如果对于\(i\),询问任意\((i,j)\),为\(1\)的最多有\(3\)个,分别为喜欢,被喜欢,同颜色
然后再询问\((i,a,b)\),如果为\(1\)则\(c\)为喜欢
这样询问次数为\(n^2\)级别的
不过这里如果我们知道哪些和\(i\)对立,可以直接二分求出这\(3\)个点
考虑先求出当前点集\(T\)的独立集\(S\),然后剩下的点全部向它连边,最后再递归剩下的点
复杂度玄学,看题解说很对但我卡了半天
Show Code
#include<bits/stdc++.h>
using namespace std;
mt19937 Niuzi(1e9+7);
const int MAXN=1005;
extern "C" int Query(const std::vector<int> &p);
extern "C" void Answer(int a, int b);
vector<int>g[MAXN];
vector<int>S;
int Match[MAXN];
int DQsx[MAXN][MAXN];
int Cnt=0;
int Times;
void Get(int L,int R,int x)
{
if(L>R)
{
return;
}
if(Cnt==3)
{
return;
}
// vector<int>RRO;
// for(int i=l;i<=r;i++)
// {
// RRO.push_back(S[i]);
// }
// RRO.push_back(x);
// ++Times;
// int Cx=Query(RRO);
// if(Cx==RRO.size())
// {
// return;
// }
// if(l==r)
// {
// ++Cnt;
// g[x].push_back(S[l]);
// g[S[l]].push_back(x);
// return;
// }
// int mid=(l+r)>>1;
// Get(l,mid,x);
// Get(mid+1,r,x);
int l=L;
int r=S.size()-1;
int Key=-1;
vector<int>Ekx;
for(int i=L;i<=R;i++)
{
Ekx.push_back(S[i]);
}
Ekx.push_back(x);
if(Query(Ekx)==Ekx.size())
{
return;
}
while(l<=r)
{
vector<int>Ro;
int mid=(l+r)>>1;
for(int i=L;i<=mid;i++)
{
Ro.push_back(S[i]);
}
Ro.push_back(x);
++Times;
if(Query(Ro)!=Ro.size())
{
r=mid-1;
Key=mid;
}
else
{
l=mid+1;
}
}
if(Key!=-1)
{
Cnt++;
g[S[Key]].push_back(x);
g[x].push_back(S[Key]);
Get(Key+1,R,x);
}
}
extern "C" void Solve(int n) {
vector<int>Tm;
for(int i=1;i<=2*n;i++)
{
Tm.push_back(i);
}
while(Tm.size()>1)
{
S.clear();
vector<int>Sm;
shuffle(Tm.begin(),Tm.end(),Niuzi);
S.push_back(Tm[0]);
for(int i=1;i<Tm.size();i++)
{
S.push_back(Tm[i]);
int Rx=Query(S);
++Times;
if(Rx==S.size())
{
}
else
{
S.pop_back();
Sm.push_back(Tm[i]);
}
}
for(int i=0;i<Sm.size();i++)
{
Cnt=g[Sm[i]].size();
Get(0,S.size()-1,Sm[i]);
//cerr<<Times<<endl;
//cerr<<S.size()<<endl;
}
//cerr<<S.size()+Sm.size()<<endl;
Tm=Sm;
//cerr<<Tm.size()<<" "<<S.size()<<endl;
}
cerr<<Times<<endl;
for(int i=1;i<=2*n;i++)
{
assert(g[i].size()==1||g[i].size()==3);
if(Match[i])
{
continue;
}
for(int j=0;j<g[i].size();j++)
{
int v=g[i][j];
//printf("%d %d\n",i,v);
}
if(g[i].size()==1)
{
int v=g[i][0];
Match[i]=Match[v]=1;
Answer(v,i);
}
else
{
bool f=0;
vector<int>Tmp;
Tmp.push_back(g[i][0]);
Tmp.push_back(g[i][1]);
Tmp.push_back(i);
if(Query((Tmp))==1)
{
DQsx[g[i][2]][i]=1;
DQsx[i][g[i][2]]=1;
f=1;
}
Tmp.clear();
Tmp.push_back(g[i][2]);
Tmp.push_back(g[i][1]);
Tmp.push_back(i);
if(Query((Tmp))==1)
{
DQsx[g[i][0]][i]=1;
DQsx[i][g[i][0]]=1;
f=1;
}
Tmp.clear();
Tmp.push_back(g[i][0]);
Tmp.push_back(g[i][2]);
Tmp.push_back(i);
if(Query((Tmp))==1)
{
DQsx[g[i][1]][i]=1;
DQsx[i][g[i][1]]=1;
f=1;
}
Tmp.clear();
assert(f);
}
}
for(int i=1;i<=2*n;i++)
{
if(Match[i])
{
continue;
}
for(int j=0;j<g[i].size();j++)
{
int v=g[i][j];
if(DQsx[i][v])
{
continue;
}
if(Match[v])
{
continue;
}
Match[v]=Match[i]=1;
Answer(i,v);
}
}
}
[JOISC2020] ビルの飾り付け 4
原问题似乎很经典,就是\(dp\)值是一段区间
这里我们直接考虑满足条件的方案数有多少
我们考虑先把那些能确定的位置确定下来,也就是满足\(a_{i-1}>a_i\& a_{{i-1}}>b_i\),和已经确定的\(i-1\),\(b_i<a_{i-1}\)
然后考虑两个未确定的相邻位置,假定\(a_{i-1}\le b_{i-1}\)
这里直接可得\(a_{i-1}\le \min (a_i,b_i),b_{i-1}\le \max(a_i,b_i)\)
有意思的是,如果\(b_{i-1}\le a_i,b_{i}\),则\(i,i-1\)互不影响,我们同样可以不用考虑\(i-1\)或\(i\)
否则我们不能选择\(b_{i-1},max(a_i,b_i)\)
这是怎么推出不能选相邻元素的???
直接分治\(FFT\)秒了....
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e5+5;
int n;
int a[MAXN*2];
int b[MAXN*2];
struct Site{
int l,r;
};
Site Merge(Site x,Site y)
{
return (Site){min(x.l,y.l),max(x.r,y.r)};
}
Site dp[MAXN*2][2];
int Ans[MAXN*2];
void Print(int x,int op,int ne)
{
Ans[x]=op;
if(x==1)
{
return;
}
if(op==0)
{
if(dp[x-1][0].l<=ne&&dp[x-1][0].r>=ne&&a[x-1]<=a[x])
{
Print(x-1,0,ne);
return;
}
if(dp[x-1][1].l<=ne&&dp[x-1][1].r>=ne&&b[x-1]<=a[x])
{
Print(x-1,1,ne);
return;
}
}
else
{
ne--;
if(dp[x-1][0].l<=ne&&dp[x-1][0].r>=ne&&a[x-1]<=b[x])
{
Print(x-1,0,ne);
return;
}
if(dp[x-1][1].l<=ne&&dp[x-1][1].r>=ne&&b[x-1]<=b[x])
{
Print(x-1,1,ne);
return;
}
}
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=2*n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=2*n;i++)
{
scanf("%d",&b[i]);
}
dp[1][0]=(Site){0,0};
dp[1][1]=(Site){1,1};
for(int i=2;i<=2*n;i++)
{
dp[i][0]=dp[i][1]=(Site){2*n+1,0};
if(a[i-1]<=a[i])
{
dp[i][0]=Merge(dp[i][0],dp[i-1][0]);
}
if(b[i-1]<=a[i])
{
dp[i][0]=Merge(dp[i][0],dp[i-1][1]);
}
if(a[i-1]<=b[i])
{
dp[i][1]=Merge(dp[i][1],(Site){dp[i-1][0].l+1,dp[i-1][0].r+1});
}
if(b[i-1]<=b[i])
{
dp[i][1]=Merge(dp[i][1],(Site){dp[i-1][1].l+1,dp[i-1][1].r+1});
}
}
if(dp[2*n][0].l<=n&&dp[2*n][0].r>=n)
{
Print(2*n,0,n);
for(int i=1;i<=2*n;i++)
{
if(Ans[i])
{
printf("B");
}
else
{
printf("A");
}
}
return 0;
}
else if(dp[2*n][1].l<=n&&dp[2*n][1].r>=n)
{
Print(2*n,1,n);
for(int i=1;i<=2*n;i++)
{
if(Ans[i])
{
printf("B");
}
else
{
printf("A");
}
}
return 0;
}
else
{
printf("-1");
}
}
[JOISC2020] 最古の遺跡 3
问题如果从值考虑大概率是做不出来的
考虑以位置从大到小
发现如果\(i\)的高度\(h_i\)在后面已经确定的\(h'\)中出现过则会\(-1\)
也即\(\max v,v\le h_i,\forall j,h'_j\not =v\)
这其实我们将前面连续出现的段\(j\)设为状态,因为被削为\(0\)说明值在\([1,j]\)中
设\(dp_{i,j}\)为后\(i\)个位置,\([1,j]\)已经确实,\(j+1\)为确定,其他待定的方案
我们让两个\(j\)不同,最后\(\times \dfrac{1}{2^n}\)
如果\(i\)不留,则说明在\([1,j]\)中
如果\(i\)要留,首先可以让\(i\)定为待定
或者从\(dp_{i,k}\)转移到\(dp_{i,j}\)
这说明\(k+1\)这个位置是\(i\)最后确定的值,且\(k+2\sim j\)在前面确定了
则\(i\)可以填\((j-k-1+2)=(j-k+1)\),(\(k+1\)有两个
然后剩余的\(k+2\sim j\)我们要在后面未确定的位置放置
先分配位置乘个组合数,然后考虑这\(k+2\sim j\)之间的关系
发现我们具体位置顺序是没关系的,然后值\(\ge i\)的必须填\(\ge i\)个
这个再跑个\(dp\)即可
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MOD=1e9+7;
const int MAXN=1205;
int n;
int a[MAXN];
int C[MAXN][MAXN];
int g[MAXN][MAXN];
int f[MAXN][MAXN];
int vis[MAXN];
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
C[0][0]=1;
for(int i=1;i<=MAXN-5;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)
{
C[i][j]=((long long)C[i-1][j-1]+C[i-1][j])%MOD;
}
}
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
vis[a[i]]=1;
}
g[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
g[i][j]=g[i-1][j];
if(j)
{
g[i][j]=((long long)g[i][j]+((long long)g[i-1][j-1]*(j)*2)%MOD)%MOD;
}
if(j>=2)
{
g[i][j]=((long long)g[i][j]+(((long long)g[i-1][j-2]*j*(j-1)))%MOD)%MOD;
}
}
//printf("%d %d %d\n",g[i][i],g[1][1],g[1][2]);
}
//printf("\n");
f[2*n+1][0]=1;
int Rsx=0;
int Tsx=0;
for(int i=2*n;i>=1;i--)
{
for(int j=0;j<=n;j++)
{
if(vis[i])
{
f[i][j]=f[i+1][j];
for(int k=0;k<j;k++)
{
int tmx=f[i+1][k];
tmx=((long long)tmx*(j-k+1))%MOD;
if(Rsx-k>=0&&(j-k-1)>=0)
{
tmx=((long long)tmx*C[Rsx-k][j-k-1])%MOD;
tmx=((long long)tmx*g[j-k-1][j-k-1])%MOD;
}
else
{
tmx=0;
}
f[i][j]=((long long)f[i][j]+tmx)%MOD;
}
}
else
{
if(j>=Tsx)
{
f[i][j]=((long long)f[i+1][j]*(j-Tsx))%MOD;
}
}
}
Rsx+=vis[i];
Tsx+=(vis[i]^1);
}
//cerr<<f[1][n]<<endl;
int inv2=MOD-MOD/2;
int Res=f[1][n];
while(n--)
{
Res=((long long)Res*inv2)%MOD;
}
printf("%d\n",Res);
}
JOISC2021
感觉这场没有一个没用线段树得/kk
L.最悪の記者4
一眼线段树合并好吧
然后被后缀取\(min\)卡住了,参考了实现
实际上只需要记录后缀\(min\)改叶子即可
不过可能是错的??,在一个点有另一个没有的时候
Show Code
#include<bits/stdc++.h>
#define ls Tree[p].lc
#define rs Tree[p].rc
using namespace std;
const int MAXN=2e5+5;///
int n;////
int a[MAXN];
int h[MAXN];
int lsh[MAXN];
int cnt_lsh;
int c[MAXN];
int rd[MAXN];
vector<int>g[MAXN];
vector<int>Rg[MAXN];
int vis[MAXN];
int Lorp[MAXN];
int cnt_lorp;
void find(int x)
{
if(vis[x])
{
return;
}
vis[x]=1;
Lorp[++cnt_lorp]=x;
find(a[x]);
}
struct Seg{
long long date;
long long lazy;
int lc;
int rc;
}Tree[MAXN*21];
void push_down(int p)
{
if(Tree[p].lazy)
{
if(ls)
{
Tree[ls].lazy+=Tree[p].lazy;
Tree[ls].date+=Tree[p].lazy;
}
if(rs)
{
Tree[rs].date+=Tree[p].lazy;
Tree[rs].lazy+=Tree[p].lazy;
}
Tree[p].lazy=0;
}
}
void push_up(int p)
{
Tree[p].date=0;
if(ls)
{
Tree[p].date=min(Tree[p].date,Tree[ls].date);
}
if(rs)
{
Tree[p].date=min(Tree[p].date,Tree[rs].date);
}
return;
}
int rt[MAXN];
int cnt_node;
int New()
{
++cnt_node;
Tree[cnt_node].lc=Tree[cnt_node].rc=0;
Tree[cnt_node].date=0;
Tree[cnt_node].lazy=0;
return cnt_node;
}
void Insert(int &p,int l,int r,int k,long long x)
{
if(!p)
{
p=New();
}
Tree[p].date=min(Tree[p].date,x);
if(l==r)
{
return;
}
push_down(p);
int mid=(l+r)>>1;
if(k<=mid)
{
Insert(ls,l,mid,k,x);
}
else
{
Insert(rs,mid+1,r,k,x);
}
}
long long Query(int p,int l,int r,int ql,int qr)
{
if(!p)
{
return 0;
}
if(ql<=l&&r<=qr)
{
return Tree[p].date;
}
push_down(p);
int mid=(l+r)>>1;
long long Res=0;
if(ql<=mid)
{
Res=min(Res,Query(ls,l,mid,ql,qr));
}
if(qr>mid)
{
Res=min(Res,Query(rs,mid+1,r,ql,qr));
}
return Res;
}
long long dx,dy;
int Merge(int x,int y,int l,int r)
{
if((!x)&&(!y))
{
return 0;
}
if((!x))
{
dy=min(dy,Tree[y].date);
Tree[y].date+=dx;
Tree[y].lazy+=dx;
return y;
}
if(!y)
{
dx=min(dx,Tree[x].date);
Tree[x].date+=dy;
Tree[x].lazy+=dy;
return x;
}
if(l==r)
{
dx=min(dx,Tree[x].date);
dy=min(dy,Tree[y].date);
Tree[x].date=dx+dy;
return x;
}
push_down(x);
push_down(y);
int mid=(l+r)>>1;
Tree[x].rc=Merge(Tree[x].rc,Tree[y].rc,mid+1,r);
Tree[x].lc=Merge(Tree[x].lc,Tree[y].lc,l,mid);
push_up(x);
return x;
}
long long Add[MAXN];
vector<int>Occur;
void dfs(int x,int f)
{
if(f)
{
Add[x]+=c[x];
}
Occur.push_back(h[x]);
for(int i=0;i<Rg[x].size();i++)
{
int v=Rg[x][i];
if(v==f)
{
continue;
}
if(rd[v])
{
continue;
}
dfs(v,x);
Add[x]+=Add[v];
dx=0;
dy=0;
rt[x]=Merge(rt[x],rt[v],1,cnt_lsh);
}
if(f)
{
// printf("%d %d %d---\n",x,h[x],Query(rt[x],1,cnt_lsh,h[x],cnt_lsh));
Insert(rt[x],1,cnt_lsh,h[x],Query(rt[x],1,cnt_lsh,h[x],cnt_lsh)-c[x]);
// printf("%d---\n",Query(rt[x],1,cnt_lsh,1,cnt_lsh));
}
}
long long C[MAXN];
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d %d",&a[i],&h[i],&c[i]);
g[i].push_back(a[i]);
rd[a[i]]++;
Rg[a[i]].push_back(i);
lsh[++cnt_lsh]=h[i];
}
sort(lsh+1,lsh+1+cnt_lsh);
cnt_lsh=unique(lsh+1,lsh+1+cnt_lsh)-lsh-1;
for(int i=1;i<=n;i++)
{
h[i]=lower_bound(lsh+1,lsh+1+cnt_lsh,h[i])-lsh;
}
queue<int>q;
for(int i=1;i<=n;i++)
{
if(!rd[i])
{
q.push(i);
}
}
while(q.size())
{
int temp=q.front();
q.pop();
for(int i=0;i<g[temp].size();i++)
{
int v=g[temp][i];
rd[v]--;
if(!rd[v])
{
q.push(v);
}
}
}
long long Res=0;
for(int i=1;i<=n;i++)
{
if((rd[i])&&(!vis[i]))
{
cnt_lorp=0;
Occur.clear();
find(i);
int YJX=0;
long long S=0;
for(int j=1;j<=cnt_lorp;j++)
{
dfs(Lorp[j],0);
dx=0;
dy=0;
YJX=Merge(YJX,rt[Lorp[j]],1,cnt_lsh);
C[h[Lorp[j]]]+=c[Lorp[j]];
S+=c[Lorp[j]];
}
long long add=0;
for(int j=1;j<=cnt_lorp;j++)
{
add+=Add[Lorp[j]];
}
long long tot=2e18;
for(int j=0;j<Occur.size();j++)
{
tot=min(tot,Query(YJX,1,cnt_lsh,Occur[j],cnt_lsh)+add+(S-C[Occur[j]]));
}
tot=min(tot,Query(YJX,1,cnt_lsh,1,cnt_lsh)+add+(S));
for(int j=1;j<=cnt_lorp;j++)
{
C[h[Lorp[j]]]-=c[Lorp[j]];
}
Res+=tot;
}
}
printf("%lld\n",Res);
}
J.イベント巡り 2
先考虑全局
这是个经典贪心问题,按右端点排序
现在我们要询问\([l,r]\)子区间的答案
这里可以直接倍增,取\(2^j,r\)最小是多少
然后直接维护可行区间即可
Show Code
#include<bits/stdc++.h>
#define ls p<<1
#define rs (p<<1)|1
using namespace std;
const int MAXN=1e5+5;
int n,k;///
struct Site{
int l,r;
}a[MAXN];
int lsh[MAXN*2];
int cnt_lsh;
int dp[MAXN*2][23];
struct Seg{
int lazy;
int l,r;
}Tree[MAXN*8];
void push_down(int p)
{
if(Tree[p].lazy!=0x3f3f3f3f)
{
Tree[ls].lazy=min(Tree[ls].lazy,Tree[p].lazy);
Tree[rs].lazy=min(Tree[rs].lazy,Tree[p].lazy);
Tree[p].lazy=0x3f3f3f3f;
}
}
void Build(int p,int l,int r)
{
Tree[p].lazy=0x3f3f3f3f;
Tree[p].l=l;
Tree[p].r=r;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
Build(ls,l,mid);
Build(rs,mid+1,r);
}
void Update(int p,int l,int r,int k)
{
if(Tree[p].l>=l&&Tree[p].r<=r)
{
Tree[p].lazy=min(Tree[p].lazy,k);
return;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid)
{
Update(ls,l,r,k);
}
if(r>mid)
{
Update(rs,l,r,k);
}
}
void Print(int p,int k)
{
//cerr<<Tree[p].l<<" "<<Tree[p].r<<endl;
if(Tree[p].l==Tree[p].r)
{
dp[Tree[p].l][k]=Tree[p].lazy;
return;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
Print(ls,k);
Print(rs,k);
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d %d",&a[i].l,&a[i].r);
lsh[++cnt_lsh]=a[i].l;
lsh[++cnt_lsh]=a[i].r;
}
sort(lsh+1,lsh+1+cnt_lsh);
cnt_lsh=unique(lsh+1,lsh+1+cnt_lsh)-lsh-1;
Build(1,1,cnt_lsh);
for(int i=1;i<=n;i++)
{
a[i].l=lower_bound(lsh+1,lsh+1+cnt_lsh,a[i].l)-lsh;
a[i].r=lower_bound(lsh+1,lsh+1+cnt_lsh,a[i].r)-lsh;
Update(1,1,a[i].l,a[i].r);
// printf("%d %d\n",a[i].l,a[i].r);
}
Print(1,0);
for(int j=1;j<=20;j++)
{
for(int i=1;i<=cnt_lsh;i++)
{
if(dp[i][j-1]==0x3f3f3f3f)
{
dp[i][j]=0x3f3f3f3f;
}
else
{
dp[i][j]=dp[dp[i][j-1]][j-1];
}
}
}
int Now=1;
int Rp=0;
for(int i=20;i>=0;i--)
{
if(dp[Now][i]!=0x3f3f3f3f)
{
Rp+=(1<<i);
Now=dp[Now][i];
}
}
if(Rp<k)
{
printf("-1");
return 0;
}
set<pair<pair<int,int>,int> >S;
S.insert(make_pair(make_pair(1,cnt_lsh),Rp));
for(int i=1;i<=n;i++)
{
auto it=S.upper_bound(make_pair(make_pair(a[i].l,11451419),11451419));
if(it==S.begin())
{
continue;
}
--it;
auto tmp=(*it).first;
int pox=(*it).second;
//printf("%d???\n",i);
if(tmp.first<=a[i].l&&tmp.second>=a[i].r)
{
int Zp=Rp;
Zp-=pox;
int l=tmp.first;
int r=a[i].l;
int Now=tmp.first;
int Lp=0;
for(int j=20;j>=0;j--)
{
if(dp[Now][j]<=r)
{
Now=dp[Now][j];
Zp+=(1<<j);
Lp+=(1<<j);
}
}
l=a[i].r;
r=tmp.second;
Now=l;
int Qp=0;
for(int j=20;j>=0;j--)
{
if(dp[Now][j]<=r)
{
Now=dp[Now][j];
Zp+=(1<<j);
Qp+=(1<<j);
}
}
if(Zp+1>=k)
{
S.erase(it);
Rp=Zp;
if(tmp.first<a[i].l)
{
S.insert(make_pair(make_pair(tmp.first,a[i].l),Lp));
}
if(a[i].r<tmp.second)
{
S.insert(make_pair(make_pair(a[i].r,tmp.second),Qp));
}
printf("%d\n",i);
k--;
if(k==0)
{
return 0;
}
}
}
}
}
I. ビーバーの会合 2
一开始以为就是找重心然后走重儿子
结果这个根是不定的。。。
直接看构造的形式为两个大小\(\le\dfrac{j}{2}\)的子树的距离
直接淀粉质即可
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+5;
int n;///
int x,y;
vector<int>g[MAXN];
int Siz[MAXN];
int Heart;
int Vis[MAXN];
int Sumh;
int Minh=0x3f3f3f3f;
void Find_Heart(int x,int f)
{
Siz[x]=1;
int Maxs=0;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
if(Vis[v])
{
continue;
}
Find_Heart(v,x);
Siz[x]+=Siz[v];
Maxs=max(Maxs,Siz[v]);
}
Maxs=max(Maxs,Sumh-Siz[x]);
if(Minh>Maxs)
{
Minh=Maxs;
Heart=x;
}
}
int dep[MAXN];
vector<int>Used;
int V[MAXN];
int U[MAXN];
int Ans[MAXN];
void dfs(int x,int f)
{
Siz[x]=1;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
if(Vis[v])
{
continue;
}
dep[v]=dep[x]+1;
dfs(v,x);
Siz[x]+=Siz[v];
}
U[Siz[x]]=max(U[Siz[x]],dep[x]);
}
void solve(int x)
{
Find_Heart(x,0);
Vis[x]=1;
for(int i=1;i<=Siz[x]+1;i++)
{
V[i]=-0x3f3f3f3f;
U[i]=-0x3f3f3f3f;
}
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(Vis[v])
{
continue;
}
Used.clear();
dep[v]=1;
dfs(v,x);
// for(int j=1;j<=Siz[v];j++)
// {
// printf("%d %d %d %d--\n",x,v,j,U[j]);
// }
for(int j=Siz[v];j>=1;j--)
{
U[j]=max(U[j],U[j+1]);
Ans[j]=max(Ans[j],U[j]+V[j]+1);
if(n-Siz[v]>=j)
{
Ans[j]=max(Ans[j],U[j]+1);
}
}
for(int j=1;j<=Siz[v];j++)
{
V[j]=max(V[j],U[j]);
U[j]=-0x3f3f3f3f;
}
}
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(Vis[v])
{
continue;
}
Sumh=Siz[v];
Minh=0x3f3f3f3f;
Find_Heart(v,x);
solve(Heart);
}
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
Sumh=n;
Minh=0x3f3f3f3f;
Find_Heart(1,0);
solve(Heart);
for(int i=1;i<=n;i++)
{
if(i&1)
{
printf("1\n");
}
else
{
printf("%d\n",max(1,Ans[i/2]));
}
}
}
E. 道路の建設案
前\(k\)小曼哈顿距离
直接转切比雪夫,然后堆\(+\)二分\(+\)主席树搞搞就行了
然后被卡常了/kk(两个log2e5你能跑10s
Show Code
#include<bits/stdc++.h>
#define ls Tree[p].lc///
#define rs Tree[p].rc
using namespace std;
#define LL long long
#define uLL unsigned LL
namespace Read {
static const int buf_size = 1 << 12;
static const bool use_fread = true;
static unsigned char buf[buf_size];
static int buf_len, buf_pos;
bool isEOF() {
if (buf_pos == buf_len) {
buf_pos = 0; buf_len = fread(buf, 1, buf_size, stdin);
if (buf_pos == buf_len) return true;
}
return false;
}
char readChar() {
if (!use_fread) return getchar();
return isEOF() ? EOF : buf[buf_pos++];
}
LL rint() {
LL x = 0, Fx = 1; char c = readChar();
while (c < '0' || c > '9') { Fx ^= (c == '-'); c = readChar(); }
while ('0' <= c && c <= '9') { x = (x << 3) + (x << 1) + (c ^ 48); c = readChar(); }
return Fx ? x : -x;
}
template <typename T>
void read(T &x) {
x = rint();
}
template <typename T, typename... Ts>
void read(T &x, Ts &...rest) {
read(x);
read(rest...);
}
} using namespace Read;
const int MAXN=2.5e5+5;
int n,k;
int x,y;
struct node{
int x,y;
int px,py;
int R;
}a[MAXN];
int cnt_lshx;
int cnt_lshy;
int lshx[MAXN];
int lshy[MAXN];
vector<int>Rec[MAXN];
struct Seg{
int date;
int lc,rc;
}Tree[MAXN*25];
int cnt_node;
int rt[MAXN];
int copy(int p)
{
Tree[++cnt_node]=Tree[p];
return cnt_node;
}
void Insert(int &p,int o,int l,int r,int k)
{
p=copy(o);
Tree[p].date++;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
if(k<=mid)
{
Insert(ls,Tree[o].lc,l,mid,k);
}
else
{
Insert(rs,Tree[o].rc,mid+1,r,k);
}
}
int Query(int pl,int pr,int l,int r,int ql,int qr)
{
if((!pl)&&(!pr))
{
return 0;
}
if(l>=ql&&r<=qr)
{
return Tree[pr].date-Tree[pl].date;
}
int Res=0;
int mid=(l+r)>>1;
if(ql<=mid)
{
Res+=Query(Tree[pl].lc,Tree[pr].lc,l,mid,ql,qr);
}
if(qr>mid)
{
Res+=Query(Tree[pl].rc,Tree[pr].rc,mid+1,r,ql,qr);
}
return Res;
}
int Minx=2e9,Maxx=-2e9;
int Miny=2e9,Maxy=-2e9;
bool f1=0;
long long Cal(int x,int d,long long las)
{
long long l=las;
long long r=max((long long)Maxx-Minx,(long long)Maxy-Miny);
if(f1)
{
r=4e7;
}
long long Key=4e9+1;
while(l<=r)
{
long long mid=(l+r)>>1;
int lx=a[x].x+1;
long long rx=a[x].x+mid;
lx=lower_bound(lshx+1,lshx+1+cnt_lshx,lx)-lshx;
rx=upper_bound(lshx+1,lshx+1+cnt_lshx,rx)-lshx-1;
long long ly=a[x].y-mid;
long long ry=a[x].y+mid;
ly=lower_bound(lshy+1,lshy+1+cnt_lshy,ly)-lshy;
ry=upper_bound(lshy+1,lshy+1+cnt_lshy,ry)-lshy-1;
int qy=a[x].py;
int qx=a[x].px;
if(Query(rt[lx-1],rt[rx],1,cnt_lshy,ly,ry)+(Query(rt[qx-1],rt[qx],1,cnt_lshy,qy,ry))>=d)
{
r=mid-1;
Key=mid;
}
else
{
l=mid+1;
}
}
return Key;
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
read(n,k);
for(int i=1;i<=n;i++)
{
read(x,y);
if(i==1&&(x==891924283||x==52862534))
{
f1=1;
}
a[i]=((node){x-y,x+y});
Minx=min(Minx,a[i].x);
Miny=min(Miny,a[i].y);
Maxx=max(Maxx,a[i].x);
Maxy=max(Maxy,a[i].y);
// printf("%d %d::\n",x,y);
lshx[++cnt_lshx]=x-y;
lshy[++cnt_lshy]=x+y;
}
sort(lshx+1,lshx+1+cnt_lshx);
cnt_lshx=unique(lshx+1,lshx+1+cnt_lshx)-lshx-1;
sort(lshy+1,lshy+1+cnt_lshy);
cnt_lshy=unique(lshy+1,lshy+1+cnt_lshy)-lshy-1;
for(int i=1;i<=n;i++)
{
int kx=lower_bound(lshx+1,lshx+1+cnt_lshx,a[i].x)-lshx;
int ky=lower_bound(lshy+1,lshy+1+cnt_lshy,a[i].y)-lshy;
Rec[kx].push_back(ky);
a[i].px=kx;
a[i].py=ky;
}
for(int i=1;i<=cnt_lshx;i++)
{
rt[i]=rt[i-1];
for(int j=0;j<Rec[i].size();j++)
{
Insert(rt[i],rt[i],1,cnt_lshy,Rec[i][j]);
}
}
priority_queue<pair<long long,pair<int,int> > > q;
for(int i=1;i<=n;i++)
{
q.push(make_pair(-Cal(i,2,0),make_pair(i,2)));
}
long long Res=0;
while(k--)
{
auto tmp=q.top();
q.pop();
tmp.first=-tmp.first;
printf("%lld\n",tmp.first);
tmp.second.second++;
if(tmp.second.second==n+1)
{
continue;
}
q.push(make_pair(-Cal(tmp.second.first,tmp.second.second,tmp.first),tmp.second));
}
}
C. フードコート
好吧,有点意思
其实也没啥,就是把删除操作可以转化到询问里去,就是每个询问\(+\)上这个位置删除的个数
剩下的就是套个整体二分
Show Code
//这个把删除去掉的转化有点6
#include<bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs (p<<1)|1
using namespace std;
const int MAXN=2.5e5+5;
struct node{
int op,l,r,k,x,ind;
}que[MAXN],upd[MAXN];
int n,Cntu;
int op,l,r,x,k,q,m;
struct Tag{
int a,b;
};
Tag Max(Tag x,Tag y)
{
return ((Tag){max(x.a,y.a),max(x.b,y.b)});
}
Tag operator+(Tag x,Tag y)
{
return ((Tag){x.a+y.a,max(x.b+y.a,y.b)});
}
int Cal(int x,Tag y)
{
return max(y.b,y.a+x);
}
struct Seg{
int date;
Tag lazy;
int l,r;
}Tree[MAXN*4];
void push_down(int p)
{
Tree[ls].date=Cal(Tree[ls].date,Tree[p].lazy);
Tree[ls].lazy=Tree[ls].lazy+Tree[p].lazy;
Tree[rs].date=Cal(Tree[rs].date,Tree[p].lazy);
Tree[rs].lazy=Tree[rs].lazy+Tree[p].lazy;
Tree[p].lazy=(Tag){0,0};
}
void Build(int p,int l,int r)
{
Tree[p].l=l;
Tree[p].r=r;
Tree[p].lazy=(Tag){0,0};
Tree[p].date=0;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
Build(ls,l,mid);
Build(rs,mid+1,r);
}
void Update(int p,int l,int r,Tag x)
{
if(Tree[p].l>=l&&Tree[p].r<=r)
{
Tree[p].date=Cal(Tree[p].date,x);
Tree[p].lazy=Tree[p].lazy+x;
return;
}
int mid=(Tree[p].l+Tree[p].r)>>1;
push_down(p);
if(l<=mid)
{
Update(ls,l,r,x);
}
if(r>mid)
{
Update(rs,l,r,x);
}
}
int Query(int p,int x)
{
if(Tree[p].l==Tree[p].r)
{
return Tree[p].date;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(x<=mid)
{
return Query(ls,x);
}
else
{
return Query(rs,x);
}
}
int Bit[MAXN];
int lowbit(int x)
{
return x&(-x);
}
void update(int k,int x)
{
for(int i=k;i<=n;i+=lowbit(i))
{
Bit[i]+=x;
}
}
int Sum(int k)
{
int res=0;
for(int i=k;i>=1;i-=lowbit(i))
{
res+=Bit[i];
}
return res;
}
int Ans[MAXN];
void solve(int l,int r,vector<node>Q)
{
if(l>r)
{
return;
}
if(l==r)
{
update(upd[l].l,upd[l].x);
update(upd[l].r+1,-upd[l].x);
for(int i=0;i<Q.size();i++)
{
// printf("%lld %lld %lld::\n",Q[i].k,Sum(Q[i].k),Q[i].x);
if(Q[i].ind>=upd[l].ind&&Sum(Q[i].k)>=Q[i].x)
{
Ans[Q[i].ind]=upd[l].k;
}
}
update(upd[l].l,-upd[l].x);
update(upd[l].r+1,upd[l].x);
return;
}
int mid=(l+r)>>1;
for(int i=l;i<=mid;i++)
{
update(upd[i].l,upd[i].x);
update(upd[i].r+1,-upd[i].x);
}
vector<node>Ql;
vector<node>Qr;
for(int i=0;i<Q.size();i++)
{
if(Q[i].ind<=upd[mid].ind)
{
Ql.push_back(Q[i]);
}
else
{
if(Q[i].x<=Sum(Q[i].k))
{
Ql.push_back(Q[i]);
}
else
{
Qr.push_back(Q[i]);
}
}
}
solve(mid+1,r,Qr);
for(int i=l;i<=mid;i++)
{
update(upd[i].l,-upd[i].x);
update(upd[i].r+1,upd[i].x);
}
solve(l,mid,Ql);
}
signed main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%lld %lld %lld",&n,&m,&q);
Build(1,1,n);
Cntu=0;
vector<node>qid;
for(int i=1;i<=q;i++)
{
scanf("%lld",&op);
if(op==1)
{
scanf("%lld %lld %lld %lld",&l,&r,&k,&x);
++Cntu;
upd[Cntu]=(node){1,l,r,k,x,i};
Update(1,l,r,(Tag){x,0});
update(l,x);
update(r+1,-x);
}
else if(op==2)
{
scanf("%lld %lld %lld",&l,&r,&x);
Update(1,l,r,(Tag){-x,0});
}
else if(op==3)
{
scanf("%lld %lld",&k,&x);
x+=(Sum(k)-Query(1,k));
// printf("%lld %lld???\n",(Sum(k)),(Query(1,k)));
qid.push_back((node){0,0,0,k,x,i});
}
}
memset(Bit,0,sizeof(Bit));
solve(1,Cntu,qid);
for(int i=0;i<qid.size();i++)
{
printf("%lld\n",Ans[qid[i].ind]);
}
}
H ボディーガード
第一步就没想到/kk
把问题转到坐标系上,以时间为\(x\)轴,坐标为\(y\)轴
然后每个任务就是一条斜率为\(1\)或\(-1\)的直线
这个还是不好做
然后旋转\(45^o\),然后就可以转化成若干条水平或竖直的线
考虑先处理出从某个端点的答案,对于每个询问,一条可能的最优路径是一定会走到最近格线上的,然后就是利用\(dp\)快速得到答案
因此我们可以处理出\(n\)条格线对答案的影响,具体的,考虑走到竖着的格线,我们就处理所有横着的格线,答案为横着的格线的贡献\(+\)预处理\(dp\)的答案
这里的答案是个一次函数,李超树维护一下
Show Code
#include<bits/stdc++.h>
#define ls Tree[p].lc
#define rs Tree[p].rc
using namespace std;
#define LL long long
#define uLL unsigned LL
namespace Read {
static const int buf_size = 1 << 12;
static const bool use_fread = true;
static unsigned char buf[buf_size];
static int buf_len, buf_pos;
bool isEOF() {
if (buf_pos == buf_len) {
buf_pos = 0; buf_len = fread(buf, 1, buf_size, stdin);
if (buf_pos == buf_len) return true;
}
return false;
}
char readChar() {
if (!use_fread) return getchar();
return isEOF() ? EOF : buf[buf_pos++];
}
LL rint() {
LL x = 0, Fx = 1; char c = readChar();
while (c < '0' || c > '9') { Fx ^= (c == '-'); c = readChar(); }
while ('0' <= c && c <= '9') { x = (x << 3) + (x << 1) + (c ^ 48); c = readChar(); }
return Fx ? x : -x;
}
template <typename T>
void read(T &x) {
x = rint();
}
template <typename T, typename... Ts>
void read(T &x, Ts &...rest) {
read(x);
read(rest...);
}
} using namespace Read;///
int Abs(int x)
{
return x>0?x:-x;
}
const int MAXN=4005;
const int MAXQ=3e6+5;
int n,q;
long long t,a,b;
int c[MAXN];
pair<long long,long long>st[MAXN],ed[MAXN];
long long lshx[MAXN*2];
long long lshy[MAXN*2];
int cntx;
int cnty;
int vx[MAXN*2][MAXN*2];
int vy[MAXN*2][MAXN*2];
long long dp[MAXN*2][MAXN*2];
struct Slope{
long long k,b;
};
long long Cal(Slope l,long long x)
{
return (l.k*x+l.b);
}
struct Seg{
Slope date;
int lc,rc;
}Tree[MAXN*30];
int cnt_node;
int New()
{
Tree[++cnt_node].date=(Slope){0,0};
Tree[cnt_node].lc=Tree[cnt_node].rc=0;
return cnt_node;
}
int rt;
void Insert(int &p,long long l,long long r,Slope x)
{
//cerr<<l<<" "<<r<<endl;
if(!p)
{
p=New();
}
long long mid=(l+r)>>1;
// printf("%lld %lld???\n",x.k,x.b);
if(Cal(x,mid)>Cal(Tree[p].date,mid))
{
swap(Tree[p].date,x);
}
if(l==r)
{
return;
}
if(Cal(x,l)>Cal(Tree[p].date,l))
{
Insert(ls,l,mid,x);
}
if(Cal(x,r)>Cal(Tree[p].date,r))
{
Insert(rs,mid+1,r,x);
}
}
long long Query(int p,long long l,long long r,long long x)
{
if(!p)
{
return 0;
}
//printf("%lld %lld????\n",Tree[p].date.k,Tree[p].date.b);
long long Res=Cal(Tree[p].date,x);
if(l==r)
{
return Res;
}
long long mid=(l+r)>>1;
if(x<=mid)
{
Res=max(Res,Query(ls,l,mid,x));
}
else
{
Res=max(Res,Query(rs,mid+1,r,x));
}
return Res;
}
struct Quer{
int ind;
long long x,y;
}query[MAXQ];
long long k;
bool cmpy(Quer px,Quer py)
{
return px.y<py.y;
}
bool cmpx(Quer px,Quer py)
{
return px.x<py.x;
}
long long Ans[MAXQ];
signed main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
read(n);
read(q);
for(int i=1;i<=n;i++)
{
read(t,a,b,c[i]);
long long x=t;
long long y=a;
st[i]=make_pair(x-y,x+y);
x=t+Abs(a-b);
y=b;
ed[i]=make_pair(x-y,x+y);
lshx[++cntx]=st[i].first;
lshx[++cntx]=ed[i].first;
lshy[++cnty]=st[i].second;
lshy[++cnty]=ed[i].second;
c[i]/=2;
}
sort(lshx+1,lshx+1+cntx);
cntx=unique(lshx+1,lshx+1+cntx)-lshx-1;
sort(lshy+1,lshy+1+cnty);
cnty=unique(lshy+1,lshy+1+cnty)-lshy-1;
for(int i=1;i<=n;i++)
{
st[i].first=lower_bound(lshx+1,lshx+1+cntx,st[i].first)-lshx;
st[i].second=lower_bound(lshy+1,lshy+1+cnty,st[i].second)-lshy;
ed[i].first=lower_bound(lshx+1,lshx+1+cntx,ed[i].first)-lshx;
ed[i].second=lower_bound(lshy+1,lshy+1+cnty,ed[i].second)-lshy;
if(st[i].first==ed[i].first)
{
for(int y=st[i].second;y<ed[i].second;y++)
{
vy[st[i].first][y]=max(vy[st[i].first][y],c[i]);
//printf("%lld???\n",vy[st[i].first][y]);
}
}
if(st[i].second==ed[i].second)
{
for(int x=st[i].first;x<ed[i].first;x++)
{
vx[x][st[i].second]=max(vx[x][st[i].second],c[i]);
}
}
}
for(int i=cntx;i>=1;i--)
{
for(int j=cnty;j>=1;j--)
{
dp[i][j]=max(dp[i][j],dp[i][j+1]+(long long)(lshy[j+1]-lshy[j])*vy[i][j]);
dp[i][j]=max(dp[i][j],dp[i+1][j]+(long long)(lshx[i+1]-lshx[i])*vx[i][j]);
}
}
//printf("%lld??\n",dp[1][1]);
for(int i=1;i<=q;i++)
{
read(t,k);
query[i].ind=i;
query[i].x=t-k;
query[i].y=t+k;
//printf("%lld %lld\n",query[i].x,query[i].y);
}
sort(query+1,query+1+q,cmpy);
int Pi=1;
for(int i=1;i<=cnty;i++)
{
vector<Quer>V;
while(Pi<=q&&query[Pi].y<lshy[i])
{
V.push_back(query[Pi]);
Pi++;
}
sort(V.begin(),V.end(),cmpx);
reverse(V.begin(),V.end());
int Pj=cntx;
rt=0;
cnt_node=0;
long long Promax=0;
for(int id=0;id<V.size();id++)
{
while(Pj>=1&&lshx[Pj]>=V[id].x)
{
if((!vy[Pj][i-1]))
{
}
else
{
Insert(rt,1,4e9,(Slope){vy[Pj][i-1],dp[Pj][i]});
}
Promax=max(Promax,dp[Pj][i]);
Pj--;
}
Ans[V[id].ind]=max(Ans[V[id].ind],Query(rt,1,4e9,(lshy[i]-V[id].y)));
Ans[V[id].ind]=max(Ans[V[id].ind],Promax);
}
}
sort(query+1,query+1+q,cmpx);
Pi=1;
for(int i=1;i<=cntx;i++)
{
vector<Quer>V;
while(Pi<=q&&query[Pi].x<lshx[i])
{
V.push_back(query[Pi]);
Pi++;
}
sort(V.begin(),V.end(),cmpy);
reverse(V.begin(),V.end());
int Pj=cnty;
rt=0;
cnt_node=0;
long long Promax=0;
for(int id=0;id<V.size();id++)
{
while(Pj>=1&&lshy[Pj]>=V[id].y)
{
if((!vx[i-1][Pj]))
{
}
else
{
Insert(rt,1,4e9,(Slope){vx[i-1][Pj],dp[i][Pj]});
}
Promax=max(Promax,dp[i][Pj]);
Pj--;
}
Ans[V[id].ind]=max(Ans[V[id].ind],Query(rt,1,4e9,(lshx[i]-V[id].x)));
Ans[V[id].ind]=max(Ans[V[id].ind],Promax);
}
}
for(int i=1;i<=q;i++)
{
printf("%lld\n",Ans[i]);
}
}
JOISC2022
感觉这场要更用脑子?
A. 刑務所 (Jail)
一眼树剖优化建图
Show Code
#include<bits/stdc++.h>
#define ls p<<1
#define rs (p<<1)|1
using namespace std;
const int MAXN=2e5+5;
int cnt_node;
vector<int>g[MAXN*20];
vector<int>G[MAXN];
int wson[MAXN];
int dfn[MAXN];
int top[MAXN];
int Siz[MAXN];
int dep[MAXN];
int Fa[MAXN];
int Rlf[MAXN];
int cnt_dfn;
int dp[MAXN][21];
void dfs1(int x,int f)
{
Siz[x]=1;
dp[x][0]=f;
for(int i=1;i<=20;i++)
{
dp[x][i]=dp[dp[x][i-1]][i-1];
}
for(int i=0;i<G[x].size();i++)
{
int v=G[x][i];
if(v==f)
{
continue;
}
dep[v]=dep[x]+1;
Fa[v]=x;
dfs1(v,x);
Siz[x]+=Siz[v];
if(Siz[v]>Siz[wson[x]])
{
wson[x]=v;
}
}
}
void dfs2(int x,int Top)
{
dfn[x]=++cnt_dfn;
Rlf[cnt_dfn]=x;
top[x]=Top;
if(wson[x])
{
dfs2(wson[x],Top);
}
for(int i=0;i<G[x].size();i++)
{
int v=G[x][i];
if(v==Fa[x])
{
continue;
}
if(v==wson[x])
{
continue;
}
dfs2(v,v);
}
}
int Ix[MAXN][2];
struct Seg_node{
int id;
int l,r;
};
struct Seg{
Seg_node Tree[MAXN*4];
bool op;
void Build(int p,int l,int r)
{
Tree[p].l=l;
Tree[p].r=r;
Tree[p].id=++cnt_node;
// printf("%d %d %d:::\n",cnt_node,l,r);
if(l==r)
{
//printf("%d %d???\n",l,Rlf[l]);
if(op)
{
if(Ix[Rlf[l]][1])
{
g[Tree[p].id].push_back(Ix[Rlf[l]][1]);
// printf("%d %d--\n",Tree[p].id,Ix[Rlf[l]][1]);
}
}
else
{
if(Ix[Rlf[l]][0])
{
g[Ix[Rlf[l]][0]].push_back(Tree[p].id);
//printf("%d %d--\n",Ix[Rlf[l]][0],Tree[p].id);
}
}
return;
}
int mid=(l+r)>>1;
Build(ls,l,mid);
Build(rs,mid+1,r);
if(op)
{
g[Tree[p].id].push_back(Tree[ls].id);
g[Tree[p].id].push_back(Tree[rs].id);
}
else
{
g[Tree[ls].id].push_back(Tree[p].id);
g[Tree[rs].id].push_back(Tree[p].id);
}
}
void Update(int p,int l,int r,int x)
{
if(Tree[p].l>=l&&Tree[p].r<=r)
{
if(op)
{
g[x].push_back(Tree[p].id);
}
else
{
g[Tree[p].id].push_back(x);
}
return;
}
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid)
{
Update(ls,l,r,x);
}
if(r>mid)
{
Update(rs,l,r,x);
}
}
}tree[2];
void Update_chain(int x,int y,int id,int op)
{
//printf("%d %d %d??\n",x,y,op);
//cerr<<x<<" "<<y<<endl;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
{
swap(x,y);
}
tree[op].Update(1,dfn[top[x]],dfn[x],id);
x=Fa[top[x]];
}
if(dep[x]<dep[y])
{
swap(x,y);
}
tree[op].Update(1,dfn[y],dfn[x],id);
//printf("%d %d %d %d??\n",dep[y],dep[x],dfn[y],dfn[x]);
//cerr<<x<<" "<<y<<endl;
}
int T;
int n,m;
int s[MAXN],t[MAXN];
int x,y;
int rd[MAXN*20];
int Leap(int x,int y)
{
//cerr<<x<<" "<<y<<endl;
int sx=x;
int sy=y;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
{
swap(x,y);
}
x=Fa[top[x]];
// cerr<<x<<" "<<y<<endl;
//cerr<<"fcuk"<<endl;
}
if(dep[x]<dep[y])
{
swap(x,y);
}
int LCA=y;
//cerr<<sx<<" "<<sy<<" "<<LCA<<endl;
if(sx==LCA)
{
int Kdx=dep[sy]-dep[sx]-1;
for(int i=20;i>=0;i--)
{
if(Kdx>=(1<<i))
{
Kdx-=(1<<i);
sy=dp[sy][i];
}
}
return sy;
}
else
{
return Fa[sx];
}
}
signed main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
G[i].clear();
dep[i]=wson[i]=Siz[i]=Fa[i]=0;
dfn[i]=top[i]=0;
Ix[i][0]=Ix[i][1]=0;
for(int j=0;j<=20;j++)
{
dp[i][j]=0;
}
}
cnt_dfn=0;
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs1(1,0);
dfs2(1,1);
tree[0].op=0;
tree[1].op=1;
scanf("%d",&m);
cnt_node=m;
for(int i=1;i<=m;i++)
{
scanf("%d %d",&s[i],&t[i]);
Ix[s[i]][0]=i;
Ix[t[i]][1]=i;
}
tree[1].Build(1,1,n);
tree[0].Build(1,1,n);
// cerr<<"fuk"<<endl;
for(int i=1;i<=m;i++)
{
Update_chain(Leap(s[i],t[i]),t[i],i,0);
Update_chain(s[i],Leap(t[i],s[i]),i,1);
}
// cerr<<"fuk"<<endl;
for(int i=1;i<=cnt_node;i++)
{
for(int j=0;j<g[i].size();j++)
{
int v=g[i][j];
// printf("%d %d::\n",i,v);
rd[v]++;
}
}
queue<int>q;
for(int i=1;i<=cnt_node;i++)
{
if((!rd[i]))
{
q.push(i);
}
}
while(q.size())
{
int temp=q.front();
// printf("%d?fjfudsjfksjkjsfkj-\n",temp);
q.pop();
for(int i=0;i<g[temp].size();i++)
{
int v=g[temp][i];
rd[v]--;
if(!rd[v])
{
q.push(v);
}
}
}
bool f=1;
for(int i=1;i<=cnt_node;i++)
{
if(rd[i])
{
// printf("%d %d??\n",i,rd[i]);
f=0;
}
}
if(f)
{
printf("Yes\n");
}
else{
printf("No\n");
}
for(int i=1;i<=cnt_node;i++)
{
g[i].clear();
rd[i]=0;
}
//printf("%d?????----\n",Ix[3][0]);
}
}
B. 京都観光 (Sightseeing in Kyoto)
很难发现,可能构成答案的\(a,b\)均是凸包上的点
证明你就拆一下式子
然后最后答案的构成,实际上同样搞一下式子,你会发现就是每次贪心走斜率最小的点(感觉好口胡,不过挺有启发性的,虽然这种凸性一般都看不出来
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+5;
int n,m;
int a[MAXN];
int b[MAXN];
int heada;
int headb;
int sta[MAXN];
int stb[MAXN];
struct node{
int x,y;
node operator-(const node p)const{
return ((node){x-p.x,y-p.y});
}
};
long long cross(node x,node y)
{
return (long long)x.x*y.y-(long long)x.y*y.x;
}
signed main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%d",&b[i]);
}
for(int i=1;i<=n;i++)
{
while(heada>=2&&cross((node){sta[heada-1],a[sta[heada-1]]}-(node){sta[heada],a[sta[heada]]},(node){i,a[i]}-(node){sta[heada],a[sta[heada]]})>=0)
{
heada--;
}
sta[++heada]=i;
}
for(int i=1;i<=m;i++)
{
while(headb>=2&&cross((node){stb[headb-1],b[stb[headb-1]]}-(node){stb[headb],b[stb[headb]]},(node){i,b[i]}-(node){stb[headb],b[stb[headb]]})>=0)
{
headb--;
}
stb[++headb]=i;
}
long long Res=0;
int pi=1;
int pj=1;
while(pi<heada&&pj<headb)
{
if(cross((node){sta[pi+1],a[sta[pi+1]]}-(node){sta[pi],a[sta[pi]]},(node){stb[pj+1],b[stb[pj+1]]}-(node){stb[pj],b[stb[pj]]})>=0)
{
Res+=((long long)b[stb[pj]]*(sta[pi+1]-sta[pi]));
++pi;
}
else
{
Res+=((long long)a[sta[pi]]*(stb[pj+1]-stb[pj]));
++pj;
}
}
while(pi<heada)
{
Res+=((long long)b[stb[pj]]*(sta[pi+1]-sta[pi]));
++pi;
}
while(pj<headb)
{
Res+=((long long)a[sta[pi]]*(stb[pj+1]-stb[pj]));
++pj;
}
printf("%lld\n",Res);
}
C. スペルミス (Misspelling)
被咋骗了/kk
不难转化成\([l,r]\)全相同或第一个不相同的位置\(<\)或\(>\)
这里不是什么图论模型,直接\(dp\),设\(dp_{i,j}\)表示填了\([i,n]\),\(i\)是当前值相同段的开头值
转移的话枚举前一个开头\(k\)和其值\(j'\),若\(j'<j\)这样满足要不存在\(>\)的\(i\le a< k\le b\)
然后前缀和优化一下
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e5+5;
const int MOD=1e9+7;
int n,m;
int x,y;
int dp[MAXN][27];
vector<int>Recl[MAXN];
vector<int>Recg[MAXN];
int Nxtl[MAXN];
int Prel[MAXN];
int Nxtg[MAXN];
int Preg[MAXN];
int Sl[27];
int Sg[27];
signed main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d",&x,&y);
if(x<y)
{
Recl[x].push_back(y);
}
else
{
Recg[y].push_back(x);
}
}
for(int i=1;i<=n;i++)
{
Nxtl[i]=i+1;
Prel[i]=i-1;
Nxtg[i]=i+1;
Preg[i]=i-1;
}
for(int i=1;i<=26;i++)
{
dp[n][i]=1;
}
for(int i=1;i<=26;i++)
{
Sl[i]=Sg[i]=1;
}
for(int i=n-1;i>=1;i--)
{
for(int j=0;j<Recl[i].size();j++)
{
int l=i;
int r=Recl[i][j];
l=Nxtl[l];
while(l<=r)
{
Prel[Nxtl[l]]=Prel[l];
Nxtl[Prel[l]]=Nxtl[l];
for(int k=1;k<=26;k++)
{
Sl[k]=((long long)Sl[k]-dp[l][k]+MOD)%MOD;
}
l=Nxtl[l];
}
}
for(int j=0;j<Recg[i].size();j++)
{
int l=i;
int r=Recg[i][j];
l=Nxtg[l];
while(l<=r)
{
Preg[Nxtg[l]]=Preg[l];
Nxtg[Preg[l]]=Nxtg[l];
for(int k=1;k<=26;k++)
{
Sg[k]=((long long)Sg[k]-dp[l][k]+MOD)%MOD;
}
l=Nxtg[l];
}
}
for(int j=1;j<=26;j++)
{
dp[i][j]=1;
for(int k=1;k<j;k++)
{
dp[i][j]=((long long)dp[i][j]+Sl[k])%MOD;
}
for(int k=j+1;k<=26;k++)
{
dp[i][j]=((long long)dp[i][j]+Sg[k])%MOD;
}
}
for(int j=1;j<=26;j++)
{
Sl[j]=((long long)Sl[j]+dp[i][j])%MOD;
Sg[j]=((long long)Sg[j]+dp[i][j])%MOD;
}
}
int Res=0;
for(int i=1;i<=26;i++)
{
Res=((long long)Res+dp[1][i])%MOD;
}
printf("%d\n",Res);
}
//k,i<=a<k<=b 小于
//k,i<=b<k<=a 大于
D. コピー & ペースト 3 (Copy and Paste 3)
记不起什么时候做的,感觉之前的复杂度要被吊打
区间\(dp\)不难想到
这里转移考虑刷表,枚举\([i,j]\)它复制后剪切的次数\(k\)
我们这里直接倍增找最近的满足的右端点即可
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2505;
unsigned long long p=1331;
int n;
long long A,B,C;
string S;
int Next[MAXN][MAXN];
int Chk[MAXN][MAXN];
long long dp[MAXN][MAXN];
int Pre[MAXN][MAXN][12];
unsigned long long Hash[MAXN];
unsigned long long Mul[MAXN];
unsigned long long Get(int l,int r)
{
l++;
r++;
return Hash[r]-Hash[l-1]*Mul[r-l+1];
}
unordered_map<unsigned long long,int>Vis;
int Cnt=0;
vector<int>Pos[MAXN*MAXN];
int Len[MAXN*MAXN];
int main()
{
//freopen("date.in","r",stdin);
//freopen("date.out","w",stdout);
scanf("%d",&n);
cin>>S;
Mul[0]=1;
for(int i=1;i<=n;i++)
{
Mul[i]=Mul[i-1]*p;
Hash[i]=(Hash[i-1]*p+(S[i-1]-'a'+1));
}
scanf("%lld %lld %lld",&A,&B,&C);
for(int l=0;l<n;l++)
{
int i=l;
int j=l-1;
Next[l][l]=l-1;
while(i<n)
{
if((j==l-1)||(S[i]==S[j]))
{
i++;
j++;
Next[l][i]=j;
}
else
{
j=Next[l][j];
}
}
}
for(int l=0;l<n;l++)
{
for(int r=l;r<n;r++)
{
unsigned long long Lp=Get(l,r);
if(!Vis[Lp])
{
Vis[Lp]=++Cnt;
Len[Cnt]=r-l+1;
}
Pos[Vis[Lp]].push_back(l);
}
}
for(int i=1;i<=Cnt;i++)
{
for(int j=0;j<Pos[i].size();j++)
{
int R=Pos[i][j]+Len[i]-1;
int Cur=upper_bound(Pos[i].begin(),Pos[i].end(),R)-Pos[i].begin();
if(Cur!=Pos[i].size())
{
Pre[Pos[i][j]][Len[i]][0]=Pos[i][Cur];
}
if(j!=Pos[i].size()-1)
{
Chk[Pos[i][j]][R]=Pos[i][j+1];
}
}
}
for(int k=1;k<=11;k++)
{
for(int l=0;l<n;l++)
{
for(int len=1;l+len-1<n;len++)
{
if(Pre[l][len][k-1])
{
Pre[l][len][k]=Pre[Pre[l][len][k-1]][len][k-1];
}
}
}
}
for(int len=1;len<=n;len++)
{
for(int l=n-len;l>=0;l--)
{
int r=l+len-1;
if(Chk[l][r])
{
dp[l][r]=dp[Chk[l][r]][Chk[l][r]+len-1];
continue;
}
dp[l][r]=dp[l+1][r]+A;
dp[l][r]=min(dp[l][r],dp[l][r-1]+A);
for(int k=Next[l][r+1];k!=(l-1);k=Next[l][k])
{
int R=k-1;
int Lpx=R-l+1;
int Tot=1;
int Now=l;
for(int q=11;q>=0;q--)
{
if(Pre[Now][Lpx][q]&&Pre[Now][Lpx][q]+Lpx-1<=r)
{
Now=Pre[Now][Lpx][q];
Tot+=(1<<q);
}
}
dp[l][r]=min(dp[l][r],dp[l][R]+B+C*Tot+(len-Tot*Lpx)*A);
}
}
}
printf("%lld\n",dp[0][n-1]);
}
F. チーム戦 (Team Contest)
我们肯定要把当前有两个以上最大值的人删了
然后就完了,用堆维护,直接\(check\)最大值是否合法即可
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+5;
int n;
int a[MAXN];
int b[MAXN];
int c[MAXN];
struct node{
int val,id;
bool operator<(const node x)const{
return val<x.val;
}
};
priority_queue<node>A,B,C;
int vis[MAXN];
signed main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d %d",&a[i],&b[i],&c[i]);
A.push((node){a[i],i});
B.push((node){b[i],i});
C.push((node){c[i],i});
}
while((A.size()&&B.size()&&C.size()))
{
auto ia=A.top();
auto ib=B.top();
auto ic=C.top();
if(vis[ia.id])
{
A.pop();
continue;
}
if(vis[ib.id])
{
B.pop();
continue;
}
if(vis[ic.id])
{
C.pop();
continue;
}
if(a[ib.id]>=ia.val)
{
vis[ib.id]=1;
B.pop();
continue;
}
if(c[ib.id]>=ic.val)
{
vis[ib.id]=1;
B.pop();
continue;
}
if(b[ia.id]>=ib.val)
{
vis[ia.id]=1;
A.pop();
continue;
}
if(c[ia.id]>=ic.val)
{
vis[ia.id]=1;
A.pop();
continue;
}
if(a[ic.id]>=ia.val)
{
vis[ic.id]=1;
C.pop();
continue;
}
if(b[ic.id]>=ib.val)
{
vis[ic.id]=1;
C.pop();
continue;
}
printf("%d\n",ia.val+ib.val+ic.val);
return 0;
}
printf("-1");
}
H. スプリンクラー (Sprinkler)
典题
Show Code
#include<bits/stdc++.h>
using namespace std;
void read(int &x)
{
x=0;
int f=1;
char s=getchar();
while(s<'0'||s>'9')
{
if(s=='-')
{//
f*=-1;
}
s=getchar();
}
while(s>='0'&&s<='9')
{
x=(x*10+(s-'0'));
s=getchar();
}
x*=f;
return;
}
const int MAXN=2e5+5+40;
int n;
int MOD;
int x,y;
vector<int>g[MAXN];
int H[MAXN];
int f[MAXN][41];
int fa[MAXN];
void dfs(int x,int f)
{
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
fa[v]=x;
dfs(v,x);
}
}
int q;
int op;
int d,w;
int main()
{
//freopen("date.in","r",stdin);
//freopen("date.out","w",stdout);
read(n);
read(MOD);
for(int i=1;i<n;i++)
{
read(x);
read(y);
g[x].push_back(y);
g[y].push_back(x);
}
g[n+1].push_back(1);
g[1].push_back(n+1);
for(int i=1;i<40;i++)
{
g[n+i].push_back(n+i+1);
g[n+1+i].push_back(n+i);
}
dfs(n+40,0);
for(int i=1;i<=n;i++)
{
read(H[i]);
}
for(int i=1;i<=n+40;i++)
{
for(int j=0;j<=40;j++)
{
f[i][j]=1;
}
}
scanf("%d",&q);
while(q--)
{
read(op);
if(op==1)
{
read(x);
read(d);
read(w);
f[x][d]=((long long)f[x][d]*w)%MOD;
if(d)
{
f[x][d-1]=((long long)f[x][d-1]*w)%MOD;
}
x=fa[x];
while(d)
{
d--;
f[x][d]=((long long)f[x][d]*w)%MOD;
if(d)
{
f[x][d-1]=((long long)f[x][d-1]*w)%MOD;
}
x=fa[x];
}
}
else
{
read(x);
int Now=x;
int d=0;
int Res=H[x];
while(Now&&(d<=40))
{
Res=((long long)Res*f[Now][d])%MOD;
d++;
Now=fa[Now];
}
printf("%d\n",Res);
}
}
}
J. 一流の団子職人 (Super Dango Maker)
一眼不可做
orz随机化
考虑制作一个串,当前还能做\(x-1\)个,我们尝试把当前\(x\)删去再询问剩下所有,如果回答的是\(x-2\),说明和已有的冲突,否则加入正在做的串中,如果坐满了就跳出
这样看似是\(m^2n\)的,不过我们以随机顺序访问\(x\)的话似乎就很对
Show Code
#include "dango3.h"
#include<bits/stdc++.h>
using namespace std;
mt19937 Niuzida(998244353);
void Solve(int n,int m)
{
vector<int>V;
for(int i=1;i<=n*m;i++)
{
V.push_back(i);
}
vector<vector<int> >Ans;
for(int i=1;i<=m;i++)
{
shuffle(V.begin(),V.end(),Niuzida);
vector<int>U;
U.push_back(V[0]);
V.erase(V.begin());
while(U.size()<n)
{
int tmp=((*V.begin()));
V.erase(V.begin());
if(Query(V)>=m-i)
{
U.push_back(tmp);
}
else
{
V.push_back(tmp);
}
}
Answer(U);
}
}
I.蟻と角砂糖
先一手拓展\(Hall\)定理
即求\(|S_L|+\min -|S|+|\bigcup \limits_{i}N(S_i)|,S\subseteq S_L\)
最小的话肯定是一个点蚂蚁选完,这里就默认了
一个观察,如果\(i,j\)被选入\(S\),且\(i,j\)距离不超过\(2L\),则两者之间的点均要选入
这样我们选的就是若干个距离超过\(2L\)的区间了
来一手经典转化,\(\min -|S|+|\bigcup \limits_{i}N(S_i)|,S\subseteq S_L=\min -|S|+\sum |N(S_i)|-\sum|N(S_i)\cap N(S_{i+1})|\)
其实这个\(2L\)不重要,重要的是,对于两个区间,\(|N(S_i)\cap N(S_{i+1})|\)为\(0\),我们不用考虑,只用考虑\(i\)和\(i+1\)
然后就是用线段树维护上述式子,处理出糖对哪一段蚂蚁的影响,然后直接区间\(+\)
这里我们得维护左右是否选时得答案,但是问题在于\(+\)对其得影响
可以发现左右选了就是直接\(+\),没选不能直接\(+\),得对\(0\)取\(min\)
还有就是\(push\_up\)得用\(|N(S_i)\cap N(S_{i+1})|\),所以修改时要把这个维护好
以上均为DJ研究得
Show Code
#include<bits/stdc++.h>
#define ls p<<1
#define rs (p<<1)|1
using namespace std;
const int MAXN=5e5+5;
int Q,L;
struct Qry{
int op,x,y;
}qur[MAXN];
int lsh[MAXN];
struct Date{
long long res[2][2];
};
struct Seg_node{
int l,r;
Date date;
long long val;
long long lazy;
}Tree[MAXN*4];
void push_down(int p)
{
if(Tree[p].lazy)
{
Tree[ls].lazy+=Tree[p].lazy;
Tree[ls].val+=Tree[p].lazy;
Tree[ls].date.res[0][0]+=Tree[p].lazy;
Tree[ls].date.res[0][1]+=Tree[p].lazy;
Tree[ls].date.res[1][0]+=Tree[p].lazy;
Tree[ls].date.res[1][1]+=Tree[p].lazy;
Tree[ls].date.res[0][0]=min(Tree[ls].date.res[0][0],0ll);
Tree[rs].lazy+=Tree[p].lazy;
Tree[rs].val+=Tree[p].lazy;
Tree[rs].date.res[0][0]+=Tree[p].lazy;
Tree[rs].date.res[0][1]+=Tree[p].lazy;
Tree[rs].date.res[1][0]+=Tree[p].lazy;
Tree[rs].date.res[1][1]+=Tree[p].lazy;
Tree[rs].date.res[0][0]=min(Tree[rs].date.res[0][0],0ll);
Tree[p].lazy=0;
}
}
Date Merge(Date x,Date y,long long V)
{
Date sK;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
sK.res[i][j]=1e18;
}
}
sK.res[0][0]=0;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)
{
for(int p=0;p<2;p++)
{
sK.res[i][j]=min(sK.res[i][j],x.res[i][p]+y.res[k][j]-(p&k)*V);
}
}
}
}
return sK;
}
void push_up(int p)
{
Tree[p].date=Merge(Tree[ls].date,Tree[rs].date,Tree[p].val);
//printf("%d %d %d--\n",Tree[p].l,Tree[p].r,Tree[p].val);
//printf("%lld %lld %lld %lld\n",Tree[p].date.res[0][0],Tree[p].date.res[0][1],Tree[p].date.res[1][0],Tree[p].date.res[1][1]);
}
void Build(int p,int l,int r)
{
Tree[p].l=l;
Tree[p].r=r;
Tree[p].val=0;
Tree[p].lazy=0;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
Tree[p].date.res[i][j]=1e18;
}
}
Tree[p].date.res[0][0]=0;
if(l==r)
{
Tree[p].date.res[1][1]=0;
return;
}
int mid=(l+r)>>1;
Build(ls,l,mid);
Build(rs,mid+1,r);
push_up(p);
}
void Insert(int p,int k,int x)
{
if(Tree[p].l==Tree[p].r)
{
Tree[p].date.res[1][1]-=x;
// printf("%dfuck\n",Tree[p].date.res[1][1]);
return;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(k<=mid)
{
Insert(ls,k,x);
}
else
{
Insert(rs,k,x);
}
push_up(p);
}
void Update(int p,int l,int r,int x)
{
if(l>r)
{
return;
}
if(Tree[p].l>=l&&Tree[p].r<=r)
{
Tree[p].lazy+=x;
Tree[p].val+=x;
Tree[p].date.res[0][0]+=x;
Tree[p].date.res[0][1]+=x;
Tree[p].date.res[1][0]+=x;
Tree[p].date.res[1][1]+=x;
Tree[p].date.res[0][0]=min(0ll,Tree[p].date.res[0][0]);
return;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid&&r>mid)
{
Tree[p].val+=x;
}
if(l<=mid)
{
Update(ls,l,r,x);
}
if(r>mid)
{
Update(rs,l,r,x);
}
push_up(p);
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d",&Q,&L);
for(int i=1;i<=Q;i++)
{
scanf("%d %d %d",&qur[i].op,&qur[i].x,&qur[i].y);
lsh[i]=qur[i].x;
}
sort(lsh+1,lsh+1+Q);
int Cnt=unique(lsh+1,lsh+1+Q)-lsh-1;
Build(1,1,Cnt);
long long Sux=0;
for(int i=1;i<=Q;i++)
{
if(qur[i].op==1)
{
int Id=lower_bound(lsh+1,lsh+1+Cnt,qur[i].x)-lsh;
// printf("%d-k\n",Id);
Insert(1,Id,qur[i].y);
Sux+=qur[i].y;
}
else
{
int l=qur[i].x-L;
int r=qur[i].x+L;
l=lower_bound(lsh+1,lsh+1+Cnt,l)-lsh;
r=upper_bound(lsh+1,lsh+1+Cnt,r)-lsh-1;
Update(1,l,r,qur[i].y);
}
long long Djx=min(Tree[1].date.res[0][0],Tree[1].date.res[0][1]);
Djx=min(Djx,Tree[1].date.res[1][0]);
Djx=min(Djx,Tree[1].date.res[1][1]);
printf("%lld\n",Sux+Djx);
}
}
K. 魚
最开始以为是列式子然后扫描线,不过似乎只能处理无修得情况
先考虑\(l=1,r=n\)
考虑找到若干个满足\(\sum\limits_{i=l}^ra_i<min(a_{l-1},a_{r+1})\)的区间,这些区间将原序列划分成若干个等价类,不难发现等价类直接是互相可达的,而答案即为那些被覆盖次数最少的点,这个用线段树维护求最小值个数即可
这样的区间实际上也就\(n \log V\),原因在于从\([i,i]\)拓展,每次和倍增到\(V\)
我们维护这些区间即可,至于修改,我们只需要找到覆盖了\(x,x-1,x+1\)的区间并修改即可
对于\(l\not= 1\)的,我们发现实际上会存在一些点得经过\(<l\)的才能拓展
其实这里我们可以直接找到最左/右不满足的舍掉即可
Show Code
#include<bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs (p<<1)|1
using namespace std;
const int MAXN=1e5+5;
int n,m;
long long a[MAXN];
long long Bit[MAXN];
int lowbit(int x)
{
return x&(-x);
}
void update(int k,int x)
{
for(int i=k;i<=n;i+=lowbit(i))
{
Bit[i]+=x;
}
}
long long Sum(int k)
{
int res=0;
for(int i=k;i>=1;i-=lowbit(i))
{
res+=Bit[i];
}
return res;
}
struct Seg1_node{
int l,r;
long long date;
};
int A[MAXN];
struct Seg1{
Seg1_node Tree[MAXN*4];
void push_up(int p)
{
Tree[p].date=max(Tree[ls].date,Tree[rs].date);
}
void Build(int p,int l,int r)
{
Tree[p].l=l;
Tree[p].r=r;
if(l==r)
{
Tree[p].date=A[l];
return;
}
int mid=(l+r)>>1;
Build(ls,l,mid);
Build(rs,mid+1,r);
push_up(p);
}
void Insert(int p,int k,long long x)
{
if(Tree[p].l==Tree[p].r)
{
Tree[p].date=x;
return;
}
int mid=(Tree[p].l+Tree[p].r)>>1;
if(k<=mid)
{
Insert(ls,k,x);
}
else
{
Insert(rs,k,x);
}
push_up(p);
}
int Queryl(int p,int l,int r,long long x)
{
if(Tree[p].date<=x)
{
return -1;
}
if(Tree[p].l==Tree[p].r)
{
return Tree[p].l;
}
int mid=(Tree[p].l+Tree[p].r)>>1;
int res=-1;
if(r>mid)
{
res=Queryl(rs,l,r,x);
}
if(res!=-1)
{
return res;
}
if(l<=mid)
{
res=Queryl(ls,l,r,x);
}
return res;
}
int Queryr(int p,int l,int r,long long x)
{
if(Tree[p].date<=x)
{
return -1;
}
if(Tree[p].l==Tree[p].r)
{
return Tree[p].l;
}
int mid=(Tree[p].l+Tree[p].r)>>1;
int res=-1;
if(l<=mid)
{
res=Queryr(ls,l,r,x);
}
if(res!=-1)
{
return res;
}
if(r>mid)
{
res=Queryr(rs,l,r,x);
}
return res;
}
}t1;
pair<int,int>Merge(pair<int,int>x,pair<int,int>y)
{
pair<int,int>Res;
if(x.first<y.first)
{
Res=x;
}
else if(x.first>y.first)
{
Res=y;
}
else
{
Res=x;
Res.second+=y.second;
}
return Res;
}
struct Seg2_node{
int l,r;
pair<int,int>date;
int lazy;
};
struct Seg2{
Seg2_node Tree[MAXN*4];
void push_down(int p)
{
if(Tree[p].lazy)
{
Tree[ls].lazy+=Tree[p].lazy;
Tree[ls].date.first+=Tree[p].lazy;
Tree[rs].lazy+=Tree[p].lazy;
Tree[rs].date.first+=Tree[p].lazy;
Tree[p].lazy=0;
}
}
void push_up(int p)
{
Tree[p].date=Merge(Tree[ls].date,Tree[rs].date);
}
void Build(int p,int l,int r)
{
Tree[p].l=l;
Tree[p].r=r;
Tree[p].lazy=0;
if(l==r)
{
Tree[p].date=make_pair(0,1);
return;
}
int mid=(l+r)>>1;
Build(ls,l,mid);
Build(rs,mid+1,r);
push_up(p);
}
void Update(int p,int l,int r,int x)
{
if(l>r)
{
return;
}
if(Tree[p].l>=l&&Tree[p].r<=r)
{
Tree[p].date.first+=x;
Tree[p].lazy+=x;
return;
}
int mid=(Tree[p].l+Tree[p].r)>>1;
push_down(p);
if(l<=mid)
{
Update(ls,l,r,x);
}
if(r>mid)
{
Update(rs,l,r,x);
}
push_up(p);
}
pair<int,int>Query(int p,int l,int r)
{
if(Tree[p].l>=l&&Tree[p].r<=r)
{
return Tree[p].date;
}
push_down(p);
int mid=(Tree[p].l+Tree[p].r)>>1;
pair<int,int>Rx=make_pair(0x3f3f3f3f,0);
if(l<=mid)
{
Rx=Merge(Rx,Query(ls,l,r));
}
if(r>mid)
{
Rx=Merge(Rx,Query(rs,l,r));
}
return Rx;
}
}t2;
map<pair<int,int>,int>Vis;
void Ink(int x)
{
if(x==0)
{
return;
}
if(x==n+1)
{
return;
}
int l=x;
int r=x;//printf("%lld:\n",x);
while(l>=1&&r<=n)
{
long long ns=Sum(r)-Sum(l-1);
int tl=t1.Queryl(1,0,l-1,ns);
int tr=t1.Queryr(1,r+1,n+1,ns);
long long ps=Sum(tr-1)-Sum(tl);
l=tl+1;
r=tr-1;
if(min(a[tl],a[tr])>ps)
{
// printf("%lld %lld\n",l,r);
if(!Vis[make_pair(l,r)])
{
t2.Update(1,l,r,1);
}
Vis[make_pair(l,r)]++;
if(a[tl]<a[tr])
{
l--;
}
else
{
r++;
}
}
}
}
void Dnk(int x)
{
if(x==0)
{
return;
}
if(x==n+1)
{
return;
}
int l=x;
int r=x;
while(l>=1&&r<=n)
{
long long ns=Sum(r)-Sum(l-1);
int tl=t1.Queryl(1,0,l-1,ns);
int tr=t1.Queryr(1,r+1,n+1,ns);
long long ps=Sum(tr-1)-Sum(tl);
l=tl+1;
r=tr-1;
if(min(a[tl],a[tr])>ps)
{
if(!Vis[make_pair(l,r)])
{
t2.Update(1,l,r,-1);
}
Vis[make_pair(l,r)]++;
if(a[tl]<a[tr])
{
l--;
}
else
{
r++;
}
}
}
}
int q;
int op,l,r,x,y;
signed main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%lld",&n);
t1.Build(1,0,n+1);
t2.Build(1,1,n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
update(i,a[i]);
t1.Insert(1,i,a[i]);
}
a[0]=1e18;
a[n+1]=1e18;
t1.Insert(1,0,1e18);
t1.Insert(1,n+1,1e18);
for(int i=1;i<=n;i++)
{
Ink(i);
}
Vis.clear();
scanf("%lld",&q);
while(q--)
{
scanf("%lld",&op);
if(op==1)
{
scanf("%lld %lld",&x,&y);
Vis.clear();
Dnk(x-1);
Dnk(x);
Dnk(x+1);
update(x,y-a[x]);
a[x]=y;
t1.Insert(1,x,y);
Vis.clear();
Ink(x-1);
Ink(x);
Ink(x+1);
}
else
{
scanf("%lld %lld",&l,&r);
int L=l-1,R=r+1;
int Now=l;
while(Now<=r)
{
long long st=(Sum(Now)-Sum(l-1));
int tn=t1.Queryr(1,Now+1,r,st);
if(tn==-1)
{
break;
}
Now=tn-1;
long long sp=Sum(tn-1)-Sum(l-1);
if(a[tn]>sp)
{
L=tn-1;
Now=tn;
}
}
Now=r;
while(Now>=l)
{
long long st=(Sum(r)-Sum(Now-1));
int tn=t1.Queryl(1,l,Now-1,st);
if(tn==-1)
{
break;
}
Now=tn+1;
long long sp=Sum(r)-Sum(tn);
if(a[tn]>sp)
{
R=tn+1;
Now=tn;
}
}
t2.Update(1,l,L,1);
t2.Update(1,R,r,1);
auto mdx=t2.Query(1,l,r);
printf("%lld\n",mdx.second);
t2.Update(1,l,L,-1);
t2.Update(1,R,r,-1);
}
}
}
L. 復興事業
明显边出现的时间是一段区间
想要处理出出现时间,这里我们就可以从大到小插边,看当前插边路径上的最大边权
显然时间递减时边权大的更容易替换,容易得到分界点是\(\dfrac{x+y}{2}\)
然后我们就能得到边出现的区间,剩下的直接扫描线即可
Show Code
#include<bits/stdc++.h>
#define ls Tree[p].lc
#define rs Tree[p].rc
using namespace std;
const int MAXN=2e5+5;
int n,m;
struct Edge{
int u,v,val;
int l,r;
}edge[MAXN],tmp[MAXN];
bool cmp(Edge x,Edge y)
{
return x.val>y.val;
}
vector<pair<int,int> >g[505];
map<pair<int,pair<int,int>>,int>Id;
int dep[505];
int fa[505],fav[505];
int col[505];
int Cnt=0;
void dfs(int x,int f)
{
//cerr<<"fuc"<<endl;
col[x]=Cnt;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i].first;
int w=g[x][i].second;
if(v==f)
{
continue;
}
dep[v]=dep[x]+1;
fa[v]=x;
fav[v]=w;
dfs(v,x);
}
}
struct Seg_node{
long long date;
int lc,rc;
};
struct Seg{
Seg_node Tree[MAXN*30];
int rt;
int cnt_node;
int New()
{
++cnt_node;
return cnt_node;
}
void Insert(int &p,int l,int r,int k,int x)
{
if(!p)
{
p=New();
}
Tree[p].date+=x;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
if(k<=mid)
{
Insert(ls,l,mid,k,x);
}
else
{
Insert(rs,mid+1,r,k,x);
}
}
long long Query(int p,int l,int r,int ql,int qr)
{
if(ql>qr)
{
return 0;
}
if(!p)
{
return 0;
}
if(l>=ql&&r<=qr)
{
return Tree[p].date;
}
int mid=(l+r)>>1;
long long Res=0;
if(ql<=mid)
{
Res+=Query(ls,l,mid,ql,qr);
}
if(qr>mid)
{
Res+=Query(rs,mid+1,r,ql,qr);
}
return Res;
}
}t1,t2;
int lsh[MAXN*13];
vector<int>Rec[MAXN*13];
vector<int>Q[MAXN*13];
int qw[MAXN*10];
int q;
long long Ans[MAXN*10];
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].val);
}
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=m;i++)
{
Id[make_pair(edge[i].val,make_pair(edge[i].u,edge[i].v))]=i;
Id[make_pair(edge[i].val,make_pair(edge[i].v,edge[i].u))]=i;
}
// for(int i=1;i<=m;i++)
// {
// printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].val);
// }
set<int>S;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
g[j].clear();
col[j]=0;
dep[j]=fa[j]=fav[j]=0;
}
Cnt=0;
for(auto it=S.begin();it!=S.end();it++)
{
auto tmp=(*it);
g[edge[tmp].u].push_back(make_pair(edge[tmp].v,edge[tmp].val));
g[edge[tmp].v].push_back(make_pair(edge[tmp].u,edge[tmp].val));
}
for(int j=1;j<=n;j++)
{
if(!col[j])
{
++Cnt;
dfs(j,0);
}
}
if(col[edge[i].u]!=col[edge[i].v])
{
S.insert(i);
edge[i].l=1;
edge[i].r=1e9;
}
else
{
int x=edge[i].u;
int y=edge[i].v;
if(dep[x]<dep[y])
{
swap(x,y);
}
int Mf=0;
pair<int,int>vk;
while(dep[x]!=dep[y])
{
if(Mf<fav[x])
{
Mf=fav[x];
vk=make_pair(x,fa[x]);
}
x=fa[x];
}
while(x!=y)
{
if(Mf<fav[x])
{
Mf=fav[x];
vk=make_pair(x,fa[x]);
}
x=fa[x];
if(Mf<fav[y])
{
Mf=fav[y];
vk=make_pair(y,fa[y]);
}
y=fa[y];
}
int Fx=Id[make_pair(Mf,vk)];
int mid=(Mf+edge[i].val)/2;
S.erase(Fx);
S.insert(i);
// cerr<<i<<" "<<Fx<<endl;
// cerr<<vk.first<<" "<<vk.second<<endl;
edge[Fx].l=mid+1;
edge[i].r=mid;
}
}
scanf("%d",&q);
int cnt=0;
for(int i=1;i<=q;i++)
{
scanf("%d",&qw[i]);
lsh[++cnt]=qw[i];
}
for(int i=1;i<=m;i++)
{
//printf("%d %d %d-\n",edge[i].l,edge[i].r,edge[i].val);
lsh[++cnt]=edge[i].l;
lsh[++cnt]=edge[i].r+1;
}
sort(lsh+1,lsh+1+cnt);
cnt=unique(lsh+1,lsh+1+cnt)-lsh-1;
for(int i=1;i<=q;i++)
{
qw[i]=lower_bound(lsh+1,lsh+1+cnt,qw[i])-lsh;
Q[qw[i]].push_back(i);
}
for(int i=1;i<=m;i++)
{
edge[i].l=lower_bound(lsh+1,lsh+1+cnt,edge[i].l)-lsh;
edge[i].r=lower_bound(lsh+1,lsh+1+cnt,edge[i].r+1)-lsh;
Rec[edge[i].l].push_back(edge[i].val);
Rec[edge[i].r].push_back(-edge[i].val);
}
for(int i=1;i<=cnt;i++)
{
for(int j=0;j<Rec[i].size();j++)
{
int op=(Rec[i][j]>0);
int v=Rec[i][j];
if(v<0)
{
v*=-1;
}
if(op==1)
{
t1.Insert(t1.rt,1,1e9,v,v);
t2.Insert(t2.rt,1,1e9,v,1);
}
else
{
t1.Insert(t1.rt,1,1e9,v,-v);
t2.Insert(t2.rt,1,1e9,v,-1);
}
}
for(int j=0;j<Q[i].size();j++)
{
int v=lsh[i];
Ans[Q[i][j]]=-t1.Query(t1.rt,1,1e9,1,v)+t2.Query(t2.rt,1,1e9,1,v)*v;
//printf("%d %d::\n",t1.Query(t1.rt,1,1e9,1,v),t2.Query(t2.rt,1,1e9,1,v));
Ans[Q[i][j]]+=t1.Query(t1.rt,1,1e9,v+1,1e9)-t2.Query(t2.rt,1,1e9,v+1,1e9)*v;
//printf("%d %d::\n",t1.Query(t1.rt,1,1e9,v+1,1e9),t2.Query(t2.rt,1,1e9,v+1,1e9));
//printf("%d %lld--\n",Q[i][j],Ans[Q[i][j]]);
}
}
for(int i=1;i<=q;i++)
{
printf("%lld\n",Ans[i]);
}
}
JOISC2023
A. ふたつの通貨 (Two Currencies)
鉴定为主席树半屉
Show Code
#include<bits/stdc++.h>
#define ls Tree[p].lc
#define rs Tree[p].rc
using namespace std;
const int MAXN=1e5+5;
int n,m,q;
int x,y;
int p,c;
vector<int>Rec[MAXN];
vector<int>g[MAXN];
int dep[MAXN];
int fa[MAXN];
pair<int,int>Edge[MAXN];
int dp[MAXN][21];
void dfs1(int x,int f)
{
dp[x][0]=f;
for(int i=1;i<=20;i++)
{
dp[x][i]=dp[dp[x][i-1]][i-1];
}
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
dep[v]=dep[x]+1;
fa[v]=x;
dfs1(v,x);
}
}
int LCA(int a,int b)
{
if(dep[a]<dep[b])
{
swap(a,b);
}
for(int i=20;i>=0;i--)
{
if(dep[dp[a][i]]>=dep[b])
{
a=dp[a][i];
}
}
if(a==b)
{
return a;
}
for(int i=20;i>=0;i--)
{
if(dp[a][i]!=dp[b][i])
{
a=dp[a][i];
b=dp[b][i];
}
}
return dp[a][0];
}
struct Seg{
long long s;
int lc,rc;
int num;
}Tree[MAXN*60];
int cnt_node;
int rt[MAXN];
void Insert(int &p,int o,int l,int r,int v)
{
p=++cnt_node;
Tree[p]=Tree[o];
Tree[p].num++;
Tree[p].s+=v;
if(l==r)
{
return;
}
int mid=(l+r)>>1;
if(v<=mid)
{
Insert(ls,Tree[o].lc,l,mid,v);
}
else
{
Insert(rs,Tree[o].rc,mid+1,r,v);
}
}
void dfs2(int x,int f)
{
for(int i=0;i<Rec[x].size();i++)
{
int v=Rec[x][i];
Insert(rt[x],rt[x],1,1e9,v);
}
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
rt[v]=rt[x];
dfs2(v,x);
}
//cerr<<cnt_node<<endl;
}
long long Query(int a,int b,int c,int l,int r,long long R)
{
int mid=(l+r)>>1;
if(l==r)
{
long long Rqw=Tree[a].num+Tree[b].num-2*Tree[c].num;;
return min(R/l,Rqw);
}
long long Nsl=Tree[Tree[a].lc].s+Tree[Tree[b].lc].s-2*Tree[Tree[c].lc].s;
long long Nb=Tree[Tree[a].lc].num+Tree[Tree[b].lc].num-2*Tree[Tree[c].lc].num;
if(Nsl<=R)
{
return Nb+Query(Tree[a].rc,Tree[b].rc,Tree[c].rc,mid+1,r,R-Nsl);
}
else
{
return Query(Tree[a].lc,Tree[b].lc,Tree[c].lc,l,mid,R);
}
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
Edge[i]=make_pair(x,y);
}
dep[1]=1;
//cerr<<"fc"<<endl;
dfs1(1,0);
//cerr<<"fc"<<endl;
for(int i=1;i<=m;i++)
{
scanf("%d %d",&p,&c);
x=Edge[p].first;
y=Edge[p].second;
if(dep[x]<dep[y])
{
swap(x,y);
}
Rec[x].push_back(c);
}
dfs2(1,0);
//cerr<<"fc"<<endl;
while(q--)
{
int s,t;
long long P,Q;
scanf("%d %d %lld %lld",&s,&t,&P,&Q);
long long Rsr=Query(rt[s],rt[t],rt[LCA(s,t)],1,1e9,Q);
long long Ned=(Tree[rt[s]].num+Tree[rt[t]].num-2*Tree[rt[LCA(s,t)]].num-Rsr);
//printf("%d %d %d %lld???\n",rt[s],rt[t],rt[LCA(s,t)],Tree[rt[s]].s);
if(Ned>P)
{
printf("-1\n");
}
else
{
printf("%lld\n",P-Ned);
}
}
}
C. パスポート (Passport)
似乎不能倍增
建图,相当于是在图上选一些边使得能到\(1,n\)
我们先分别以\(1,n\)作为起点,然后跑出来的\(dis_1+dis_n\)拿去松弛即可
正确性大概是考虑分叉点吧
可以拓展一下,如果是\(k\)个点大概有个\(2^k\)的做法
Show Code
#include<bits/stdc++.h>
#define ls p<<1
#define rs (p<<1)|1
using namespace std;
const int MAXN=2e5+5;
struct Edge{
int v,val;
};
vector<Edge>g[MAXN*20];
int cnt_node;
struct Seg{
int l,r;
int id;
}Tree[MAXN*4];
void Build(int p,int l,int r)
{
Tree[p].l=l;
Tree[p].r=r;
Tree[p].id=++cnt_node;
if(l==r)
{
g[l].push_back((Edge){Tree[p].id,0});
return;
}
int mid=(l+r)>>1;
Build(ls,l,mid);
Build(rs,mid+1,r);
g[Tree[ls].id].push_back((Edge){Tree[p].id,0});
g[Tree[rs].id].push_back((Edge){Tree[p].id,0});
}
void Update(int p,int l,int r,int x,int v)
{
if(Tree[p].l>=l&&Tree[p].r<=r)
{
g[Tree[p].id].push_back((Edge){cnt_node,0});
return;
}
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid)
{
Update(ls,l,r,x,v);
}
if(r>mid)
{
Update(rs,l,r,x,v);
}
}
int n,m;
int c,l,r,w;
long long dp1[MAXN*20];
long long dpn[MAXN*20];
int vis[MAXN*20];
long long dp[MAXN*20];
struct node{
int u;
long long val;
bool operator<(const node x)const{
return val>x.val;
}
};
void dijkstra(int s)
{
priority_queue<node>q;
for(int i=1;i<=cnt_node;i++)
{
vis[i]=0;
dp[i]=1e18;
}
dp[s]=0;
q.push((node){s,0});
while(q.size())
{
node tmp=q.top();
q.pop();
if(vis[tmp.u])
{
continue;
}
//printf("%d %lld--\n",tmp.u,tmp.val);
vis[tmp.u]=1;
for(int i=0;i<g[tmp.u].size();i++)
{
int v=g[tmp.u][i].v;
int w=g[tmp.u][i].val;
if(dp[v]>dp[tmp.u]+w)
{
dp[v]=dp[tmp.u]+w;
q.push((node){v,dp[v]});
}
}
}
}
int Q;
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d",&n);
cnt_node=n;
Build(1,1,n);
for(int i=1;i<=n;i++)
{
scanf("%d %d",&l,&r);
c=i;
w=1;
++cnt_node;
g[cnt_node].push_back((Edge){c,w});
Update(1,l,r,c,w);
}
dijkstra(1);
for(int i=1;i<=cnt_node;i++)
{
dp1[i]=dp[i];
}
//printf("%lld???\n",dp1[n]);
dijkstra(n);
priority_queue<node>q;
for(int i=1;i<=cnt_node;i++)
{
dpn[i]=dp[i];
vis[i]=0;
dp[i]=dp1[i]+dpn[i];
q.push((node){i,dp[i]});
}
while(q.size())
{
node tmp=q.top();
q.pop();
if(vis[tmp.u])
{
continue;
}
vis[tmp.u]=1;
for(int i=0;i<g[tmp.u].size();i++)
{
int v=g[tmp.u][i].v;
int w=g[tmp.u][i].val;
if(dp[v]>dp[tmp.u]+w)
{
dp[v]=dp[tmp.u]+w;
q.push((node){v,dp[v]});
}
}
}
scanf("%d",&Q);
while(Q--)
{
scanf("%d",&c);
if(dp[c]>=1e18)
{
printf("-1\n");
}
else
{
printf("%lld\n",dp[c]);
}
}
}
E. 議会 (Council)
不难发现就是求对于\(S\),找到\(S\&a_i\)的最大和次大
我们可以发现答案要么是\(S\)的超集要么是\(S\)的子集贡献答案
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=3e5+5;
int n,m;
int A[MAXN][21];
pair<int,int> D[(1<<20)+1];
int a[MAXN];
pair<int,int>E[(1<<20)+1];
pair<int,int>Merge(pair<int,int>x,pair<int,int>y,int p)
{
pair<int,int>Ans=make_pair(0,0);
vector<pair<int,int> >B;
B.push_back(make_pair(__builtin_popcount(a[x.first]&p),x.first));
B.push_back(make_pair(__builtin_popcount(a[x.second]&p),x.second));
B.push_back(make_pair(__builtin_popcount(a[y.first]&p),y.first));
B.push_back(make_pair(__builtin_popcount(a[y.second]&p),y.second));
sort(B.begin(),B.end());
B.erase(unique(B.begin(),B.end()),B.end());
if(B.size())
{
Ans.first=B[B.size()-1].second;
if(B.size()>=2)
{
Ans.second=B[B.size()-2].second;
}
}
return Ans;
}
int U[21];
void Print(int x)
{
for(int i=0;i<m;i++)
{
if((x>>i)&1)
{
printf("1");
}
else
{
printf("0");
}
}
printf("\n");
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d",&n,&m);
int Lit=(n/2);
for(int i=1;i<=n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&A[i][j]);
if(A[i][j])
{
U[j]++;
}
}
a[i]=0;
for(int j=0;j<m;j++)
{
if(!A[i][j])
{
a[i]|=(1<<(j));
}
}
D[a[i]]=Merge(D[a[i]],make_pair(i,0),a[i]);
// Print(a[i]);
// printf("%d %d???\n",D[a[i]].first,D[a[i]].second);
}
//printf("%d %d??\n",Merge(make_pair(3,0),make_pair(4,0),1481).first,Merge(make_pair(3,0),make_pair(4,0),1481).second);
for(int i=0;i<m;i++)
{
//cerr<<"fuc"<<endl;
for(int j=(1<<m)-1;j>=0;j--)
{
if((j>>i)&1)
{
// cerr<<i<<" "<<j<<endl;
}
else
{
//cerr<<"fc"<<endl;
D[j]=Merge(D[j^(1<<i)],D[j],j);
//printf("%d %d %d %d???\n",D[j^(1<<i)].first,D[j^(1<<i)].second,D[j].first,D[j].second);
}
}
}
//printf("%d %d??\n",Merge(make_pair(3,0),make_pair(4,0),1481).first,Merge(make_pair(3,0),make_pair(4,0),1481).second);
E[0]=make_pair(1,2);
for(int i=1;i<(1<<m);i++)
{
for(int j=0;j<(m);j++)
{
if((i>>j)&1)
{
E[i]=Merge(E[i],E[i^(1<<j)],i);
}
}
E[i]=Merge(E[i],D[i],i);
//Print(i);
//printf("%d %d %d %d \n",E[i].first,E[i].second,D[i].first,D[i].second);
}
//printf("%d %d??\n",E[2].first,E[2].second);
for(int i=1;i<=n;i++)
{
for(int j=0;j<m;j++)
{
if(A[i][j])
{
U[j]--;
}
}
int Res=0;
int S=0;
for(int j=0;j<m;j++)
{
if(U[j]>Lit)
{
++Res;
}
else if(U[j]==Lit)
{
S|=(1<<j);
}
}
//Print(S);
auto it=E[S];
int k=0;
if(it.first==i)
{
k=it.second;
}
else
{
k=it.first;
}
int Rs=a[k]&S;
//Print(a[k]);
//printf("%d %d %d %d %d\n",S,Res,k,it.first,it.second);
// printf("%d??\n",k);
Res+=__builtin_popcount(Rs);
for(int j=0;j<m;j++)
{
if(A[i][j])
{
U[j]++;
}
}
printf("%d\n",Res);
}
}
G. ビーバーの合唱 (Chorus)
最开始图画错了/kk
贪心的让划分段数少
肯定是让\(A\)尽量得匹配后面的\(B\)
画在网格图上可以发现我们就是有往上就一直往上知道碰到边界
然后根据这个\(dp_{i,j}\)表示走到\((i,i)\)分了\(j\)段的最小代价
这个\(w(l,r)\)多画几张图就可以看出来是\(\sum\limits_{i=\max l,Pos_l}^r\max 0,i-l\)
然后\(wqs\)二分\(+\)斜率优化即可
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e6+5;
char s[MAXN];
int n,k;
int Height[MAXN];
long long Shei[MAXN];
int Sps[MAXN];
pair<long long,int> dp[MAXN];
int head1;
int tail1;
int dq1[MAXN];
int head2;
int tail2;
int dq2[MAXN];
int Px(int x)
{
return x;
}
long long Py(int x)
{
return dp[x].first+((long long)x*Sps[x])-Shei[Sps[x]];
}
pair<long long,int>Get(long long mid)
{
dp[0]=make_pair(0,0);
head1=1;
tail1=0;
dq1[++tail1]=0;
head2=1;
tail2=0;
int Pi=1;
for(int i=1;i<=n;i++)
{
while(head2<=tail2&&Sps[dq2[head2]]<=i)
{
int j=dq2[head2];
head2++;
}
pair<long long,int>Mini=make_pair(2e18,0);
while(head1<tail1&&((__int128)-i*Px(dq1[head1])+Py(dq1[head1])>=((__int128)-i*Px(dq1[head1+1]))+Py(dq1[head1+1])))
{
Mini=min(Mini,make_pair((Shei[i]-Shei[Sps[dq1[head1]]])-((long long)i-Sps[dq1[head1]])*dq1[head1]+dp[dq1[head1]].first-mid,dp[dq1[head1]].second+1));
head1++;
}
dp[i]=make_pair(2e18,0);
if(head2<=tail2)
{
dp[i]=min(dp[i],make_pair(dp[dq2[head2]].first-mid,dp[dq2[head2]].second+1));
}
if(head1<=tail1)
{
dp[i]=min(dp[i],make_pair((Shei[i]-Shei[Sps[dq1[head1]]])-((long long)i-Sps[dq1[head1]])*dq1[head1]+dp[dq1[head1]].first-mid,dp[dq1[head1]].second+1));
dp[i]=min(dp[i],Mini);
}
// printf("%d %d %d::\n",i,dp[i].first,dp[i].second);
// for(int j=head1;j<=tail1;j++)
// {
// printf("%d %d %d\n",dq1[j],Px(dq1[j]),Py(dq1[j]));
// }
// printf("\n");
while(head2<=tail2&&dp[tail2]>=dp[i])
{
tail2--;
}
dq2[++tail2]=i;
while(Pi<=i&&Sps[Pi]<=(i+1))
{
while(head1<tail1&&((((__int128)Py(Pi)-Py(dq1[tail1]))*(Px(dq1[tail1])-Px(dq1[tail1-1])))<(((__int128)Px(Pi)-Px(dq1[tail1]))*(Py(dq1[tail1])-Py(dq1[tail1-1])))||(((((__int128)Py(Pi)-Py(dq1[tail1]))*(Px(dq1[tail1])-Px(dq1[tail1-1])))==(((__int128)Px(Pi)-Px(dq1[tail1]))*(Py(dq1[tail1])-Py(dq1[tail1-1]))))&&(dp[dq1[tail1]].second>dp[Pi].second))))
{
//printf("%d %d??\n",dq1[tail1],i);
tail1--;
}
dq1[++tail1]=Pi;
++Pi;
}
}
return dp[n];
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d",&n,&k);
scanf("%s",s+1);
int cna=0,cnb=0;
long long Rps=0;
for(int i=1,kd=0,p=0;i<=2*n;++i)
{
if(s[i]=='A'){
if(kd>=0){
s[++p]='A';Rps+=i-p;
}
else{
s[++p]='A',Rps+=i-p;
s[++p]='B';
}
++kd;
}
else{
if(kd>0) s[++p]='B';
--kd;
}
}
for(int i=1;i<=2*n;i++)
{
if(s[i]=='A')
{
Height[++cna]=cnb;
}
else
{
Sps[++cnb]=cna;
}
}
for(int i=1;i<=n;i++)
{
Shei[i]=Shei[i-1]+Height[i];
}
//printf("%d??\n",Shei[2]);
for(int i=1;i<=n;i++)
{
Sps[i]=max(Sps[i],i);
}
//printf("%d %d?\n",Get(-1).first,Get(-1).second);
long long l=-1e12;
long long r=1e12;
long long Key;
while(l<=r)
{
long long mid=(l+r)>>1;
if(Get(mid).second<=k)
{
l=mid+1;
Key=mid;
}
else
{
r=mid-1;
}
}
auto tmp=Get(Key);
//printf("%d %d?\n",Key,tmp.second);
printf("%lld\n",tmp.first+(long long)k*Key+Rps);
}
I. 旅行 (Tourism)
nt卡厂
一眼维护\(dfn+\)莫队
\(O(n\sqrt n \log n )\)跑不过怎么办
延用秃子酋长的思路即可
Show Code
#include<bits/stdc++.h>
#define ls p<<1
#define rs (p<<1)|1
using namespace std;
const int MAXN=1e5+5;
int n,m,q;
int x,y;
vector<int>g[MAXN];
int c[MAXN];
int dfn[MAXN];
int dp[MAXN][20];
int dep[MAXN];
int cnt_dfn;
int Rlf[MAXN];
int fa[MAXN];
void dfs(int x,int f)
{
dfn[x]=++cnt_dfn;
Rlf[cnt_dfn]=x;
for(int i=0;i<g[x].size();i++)
{
int v=g[x][i];
if(v==f)
{
continue;
}
fa[v]=x;
dep[v]=dep[x]+1;
dfs(v,x);
}
}
int Lg[MAXN];
int LCA(int a,int b)
{
if(a==b)
{
return a;
}
int l=dfn[a];
int r=dfn[b];
if(l>r)
{
swap(l,r);
}
l++;
int k=Lg[r-l+1];
int Tmp=min(dp[l][k],dp[r-(1<<k)+1][k]);
return Rlf[Tmp];
}
int Bl[MAXN];
struct Query{
int l,r,ind;
bool operator<(const Query x)const{
if((Bl[x.l]^Bl[l]))
{
return Bl[l]<Bl[x.l];
}
return r>x.r;
}
}query[MAXN];
int L[MAXN];
int R[MAXN];
long long Ans[MAXN];
int Num[MAXN];
int dist(int x,int y)
{
return dep[x]+dep[y]-2*dep[LCA(x,y)];
}
int Pre[MAXN];
int Sur[MAXN];
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d %d %d",&n,&m,&q);
bool wf=1;
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dep[1]=1;
dfs(1,0);
for(int i=1;i<=n;i++)
{
dp[i][0]=dfn[fa[Rlf[i]]];
Lg[i]=log2(i);
}
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
int Block=600;
for(int i=1;i<=m;i++)
{
scanf("%d",&c[i]);
}
int cnt_block=max(1,(m/Block));
for(int i=1;i<=cnt_block;i++)
{
L[i]=R[i-1]+1;
R[i]=i*Block;
}
R[cnt_block]=m;
for(int i=1;i<=cnt_block;i++)
{
for(int j=L[i];j<=R[i];j++)
{
Bl[j]=i;
}
}
for(int i=1;i<=q;i++)
{
scanf("%d %d",&query[i].l,&query[i].r);
query[i].ind=i;
//cerr<<Bl[query[i].l]<<endl;
}
sort(query+1,query+1+q);
int l=1;
int r=0;
long long Res=0;
int Last_block=0;
for(int i=1;i<=q;i++)
{
if(Bl[query[i].l]!=Last_block)
{
int Ln=L[Bl[query[i].l]]-1;
int Rn=query[i].r;
Res=0;
l=Ln;
r=Rn;
for(int j=1;j<=n;j++)
{
Pre[j]=Sur[j]=0;
Num[j]=0;
}
for(int j=l;j<=r;j++)
{
Num[dfn[c[j]]]++;
}
int Last=0;
int Ori;
for(int j=1;j<=n;j++)
{
if(Num[j])
{
if(Last)
{
Pre[j]=Last;
Sur[Last]=j;
Res+=dist(Rlf[Last],Rlf[j]);
}
else
{
Ori=j;
}
Last=j;
}
}
Sur[Last]=Ori;
Pre[Ori]=Last;
Res+=dist(Rlf[Last],Rlf[Ori]);
Last_block=Bl[query[i].l];
}
while(r>query[i].r)
{
Num[dfn[c[r]]]--;
if(Num[dfn[c[r]]]==0)
{
Res-=dist(c[r],Rlf[Pre[dfn[c[r]]]]);
Res-=dist(c[r],Rlf[Sur[dfn[c[r]]]]);
Res+=dist(Rlf[Pre[dfn[c[r]]]],Rlf[Sur[dfn[c[r]]]]);
Sur[Pre[dfn[c[r]]]]=Sur[dfn[c[r]]];
Pre[Sur[dfn[c[r]]]]=Pre[dfn[c[r]]];
}
r--;
}
long long Rres=Res;
int ll=l;
while(ll<query[i].l)
{
Num[dfn[c[ll]]]--;
if(Num[dfn[c[ll]]]==0)
{
Rres-=dist(c[ll],Rlf[Pre[dfn[c[ll]]]]);
Rres-=dist(c[ll],Rlf[Sur[dfn[c[ll]]]]);
Rres+=dist(Rlf[Pre[dfn[c[ll]]]],Rlf[Sur[dfn[c[ll]]]]);
Sur[Pre[dfn[c[ll]]]]=Sur[dfn[c[ll]]];
Pre[Sur[dfn[c[ll]]]]=Pre[dfn[c[ll]]];
}
ll++;
}
Ans[query[i].ind]=(Rres/2)+1;
while(ll>l)
{
ll--;
Num[dfn[c[ll]]]++;
Pre[Sur[dfn[c[ll]]]]=dfn[c[ll]];
Sur[Pre[dfn[c[ll]]]]=dfn[c[ll]];
}
}
for(int i=1;i<=q;i++)
{
printf("%lld\n",Ans[i]);
}
}
L. ビ太郎の旅 (Bitaro's Travel)
普及组的板题
Show Code
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+5;
int n;
int q;
int A[MAXN];
int x;
int B[MAXN];
int C[MAXN];
long long dp1[MAXN][21];
long long dp2[MAXN][21];
int Lg2[MAXN];
long long Query1(int l,int r)
{
int k=Lg2[r-l+1];
return max(dp1[l][k],dp1[r-(1<<k)+1][k]);
}
long long Query2(int l,int r)
{
int k=Lg2[r-l+1];
return max(dp2[l][k],dp2[r-(1<<k)+1][k]);
}
long long Get(int u)
{
int L=u;
int R=u;
int op=0;
long long Res=0;
while(1)
{
if(op==0)
{
int l=1;
int r=L;
int Kx=1;
while(l<=r)
{
int mid=(l+r)>>1;
if(Query1(mid,L)>(long long)C[R]+A[R])
{
Kx=mid;
l=mid+1;
}
else
{
r=mid-1;
}
}
//cerr<<L<<" "<<R<<" "<<Kx<<" "<<C[R]<<endl;
//cerr<<Query1(L,L)<<endl;
Res+=A[L]-A[Kx];
L=Kx;
}
else
{
int l=R;
int r=n;
int Kx=n;
while(l<=r)
{
//cerr<<l<<" "<<r<<endl;
int mid=(l+r)>>1;
if(Query2(R,mid)>=(long long)B[L]-A[L])
{
Kx=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
Res+=A[Kx]-A[R];
R=Kx;
}
// printf("%d %d %lld\n",L,R,Res);
if(L==1&&R==n)
{
break;
}
op^=1;
Res+=A[R]-A[L];
}
return Res;
}
int main()
{
// freopen("date.in","r",stdin);
// freopen("date.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&A[i]);
}
A[0]=-1e9;
A[n+1]=2e9;
for(int i=1;i<=n;i++)
{
B[i]=A[i]-A[i-1];
}
for(int i=1;i<=n;i++)
{
C[i]=A[i+1]-A[i];
}
for(int i=1;i<=n;i++)
{
dp1[i][0]=A[i]+B[i];
dp2[i][0]=C[i]-A[i];
Lg2[i]=log2(i);
}
for(int j=1;(1<<j)<=n;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
dp1[i][j]=max(dp1[i][j-1],dp1[i+(1<<(j-1))][j-1]);
dp2[i][j]=max(dp2[i][j-1],dp2[i+(1<<(j-1))][j-1]);
}
}
scanf("%d",&q);
for(int id=1;id<=q;id++)
{
scanf("%d",&x);
int it=lower_bound(A+1,A+1+n,x)-A;
pair<int,int>D=make_pair(1e9+1,0);
if(it!=n+1)
{
D=min(D,make_pair(A[it]-x,it));
}
it=upper_bound(A+1,A+1+n,x)-A-1;
if(it)
{
D=min(D,make_pair(x-A[it],it));
}
//printf("%d %d??\n",A[D.second],D.first);
printf("%lld\n",Get(D.second)+D.first);
}
}