建瓯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);
    }
}

posted @ 2023-12-05 08:01  kid_magic  阅读(43)  评论(1编辑  收藏  举报