JOISC 2020 DAY3

Day 3

T1

问题可以变成在树上选若干不相交的链使得权值和最大,这是个简单数据结构维护 \(dp\)

#include<bits/stdc++.h>
using namespace std;
const int N = 4e5+5;
typedef long long ll;
typedef pair<int,int> pi;
int n;
pi st[20][N];int lg[N];
inline void init(int n){
	lg[1]=0;for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
	for(int i=1;1<<i<=n;i++){
		for(int j=1;j+(1<<i)-1<=n;j++){
			st[i][j]=max(st[i-1][j],st[i-1][j+(1<<(i-1))]);
		}
	}
}
int anc[N][20],par[N],cnt;
int h[N],id[N];
vector<int> ch[N];
inline pi qmax(int l,int r){
	int g = lg[r-l+1];
	return max(st[g][l],st[g][r-(1<<g)+1]);
}
inline void build_tr(int l,int r,int fa){
	if(l>r)return ;
	int g = qmax(l,r).second;
	int hgt = st[0][g].first;
	if(hgt == h[fa]){
		id[g] = fa;
	}else{
		id[g] = ++cnt;
		h[cnt]=hgt;
		par[cnt] = fa;
		ch[fa].push_back(cnt);
	}
	build_tr(l,g-1,id[g]);
	build_tr(g+1,r,id[g]);
}
int In[N], Out[N], num;
inline void dfs(int x,int pre){
	anc[x][0]=pre;
	In[x] = ++num;
	for(int i=1;i<=19;i++)anc[x][i]=anc[anc[x][i-1]][i-1];
	for(size_t i=0;i<ch[x].size();i++){
		int v = ch[x][i];
		dfs(v,x);
	}
	Out[x] = num;
}
ll t[N<<2];
inline void add(int x,int l,int r,int ql,int qr,ll s){
	if(ql<=l&&qr>=r){
		t[x]+=s;
		return ;
	}
	int mid = (l+r)>>1;
	if(ql<=mid)add(x<<1,l,mid,ql,qr,s);
	if(qr>mid)add(x<<1|1,mid+1,r,ql,qr,s);
}
inline ll qry(int x,int l,int r,int q){
	if(l==r)return t[x];int mid = (l+r)>>1;
	if(q<=mid)return t[x]+qry(x<<1,l,mid,q);
	else return t[x]+qry(x<<1|1,mid+1,r,q);
}
int m;
vector<pi> Star[N];
ll f[N];
inline void Dp(int x,int pre){
	for(size_t i=0;i<ch[x].size();i++){
		int v=ch[x][i];
		Dp(v,x);
		f[x] += f[v];
	}
	for(size_t i=0;i<ch[x].size();i++){
		int v=ch[x][i];
		add(1,1,num,In[x],Out[x],f[v]);
		add(1,1,num,In[v],Out[v],-f[v]);
	}
	for(size_t i=0;i<Star[x].size();i++){
		int low = Star[x][i].first, cost = Star[x][i].second;
		f[x] = max(f[x], qry(1,1,num,In[low])+cost);
	}
}

int main()
{
	cin >> n;
	for(int i=1;i<=n;i++){
		scanf("%d",&st[0][i].first);
		st[0][i].second=i;
	}
	h[0]=0x3f3f3f3f;
	init(n);
	build_tr(1,n,0);
	dfs(1,0);
	cin >> m;
	ll all = 0;
	for(int i=1;i<=m;i++){
		int x,y;scanf("%d%d",&x,&y);
		int c;scanf("%d",&c);
		all += c;
		int Low = id[x];
		int Upper = id[x];
		for(int j=19;~j;j--){
			if(h[anc[Upper][j]]<y)Upper = anc[Upper][j];
		}
		Star[Upper].push_back(pi(Low,c));
	}
	Dp(1,0);
	printf("%lld\n",all-f[1]);
}

T3

\(B=0\) 的部分每条边染成 \(min(dis[u],dis[v])+1\bmod 3\)

剩下的部分如果度数 \(>2\) 则染成入边不一样的颜色,否则可以构造出来这样一个序列:

\(101100101100101100\cdots\),在链上按顺序填即可。

如果连续走了三个度数为 \(2\) 的点,那么可以得到五个边,则看能否匹配确定方向即可。

Anthony.cpp:

#include "Anthony.h"
#include <vector>
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int c[N],d[N];
typedef pair<int,int> pi;
vector<pi> g[N];
vector<int> X;
inline void Solve1(){
	queue<int> q;
	q.push(0);
	d[0]=1;
	while(q.size()){
		int u=q.front();q.pop();
		for(size_t i=0;i<g[u].size();i++){
			int v=g[u][i].first;
			if(!d[v])d[v]=d[u]+1,q.push(v);
			if(d[v]>d[u]){
				X[g[u][i].second]=d[v]%3;
			}
			if(d[v]==d[u]){
				X[g[u][i].second]=(d[v]+1)%3;
			}
		}
	}	
}
int s[6]={1,0,1,1,0,0};

inline void dfs(int x,int pre){
	int deg = g[x].size();
	for(size_t i=0;i<g[x].size();i++){
		int v=g[x][i].first;if(v==pre)continue;
		if(deg==2){
			d[v]=d[x]+1;
			d[v]%=6;
			X[g[x][i].second]=s[d[v]];
		}else{
			int tmp = X[g[x][i].second] = s[d[x]]^1;
			d[v] = tmp?0:1;
		}
		dfs(v,x);
	}
}

std::vector<int> Mark(int N, int M, int A, int B,
                      std::vector<int> U, std::vector<int> V) {
	X = std::vector<int> (M);
	for(size_t i=0;i<M;i++){
		g[U[i]].push_back(pi(V[i],i));
		g[V[i]].push_back(pi(U[i],i));
	}
	if(B==0){
		Solve1();
	}else{
		dfs(0,-1);
	}
	return X;
}

Catherine.cpp

#include "Catherine.h"
#include <vector>
#include<bits/stdc++.h>
using namespace std;
int A, B;
int type = 0;
namespace Solve1{
	int pst=-1;
	int Do(vector<int> y){
//		if(pst!=-1)y[pst]++;
		int cur = -1;
		for(int i=0;i<3;i++)
			if(y[i]>0){
				if(cur==-1)cur = i;
				else if((i+1)%3==cur){
					cur=i;
				}
			}
		pst=cur;
		return cur;
	}
}

namespace Solve2{
	int s[6]={1,0,1,1,0,0};
	int dirc=0,pst=-1;
	vector<int> S;
	int Do(vector<int> y){
		int deg=(pst!=-1);
		deg+=y[0]+y[1];
		if(dirc){
			if(deg==2){
				for(int i=0;i<2;i++)if(y[i]){
					return pst=i;
				}
			}
			if(pst!=-1)y[pst]++;
			for(int i=0;i<2;i++)if(y[i]==1&&i!=pst){
				return pst=i;
			}
		}else{
			if(deg>2){
				if(pst!=-1)y[pst]++;
				dirc=1;
				for(int i=0;i<2;i++){
					if(y[i]==1){
						if(i==pst)return -1;
						return pst=i;
					}
				}
			}else if(deg==2){
				int Dir=y[0]?0:1;
				y[Dir]--;
				int Dir2 = pst==-1?(y[0]?0:1):pst;
				if(!S.size())S.push_back(Dir2);
				S.push_back(Dir);
				if(S.size()==5){
					dirc=1;
					for(int i=0;i<6;i++){
						int c=0;
						for(int j=0;j<5;j++){
							if(s[(i+j)%6]==S[j])c++;
						}
						if(c==5){
							return -1;
						}
					}
					return pst=Dir;
				}
				return pst=Dir;
			}else if(deg==1){
				int dir = pst==-1?(y[0]?0:1):-1;
				dirc=1;
				if(dir!=-1)pst=dir;
				return dir;
			}
		}
	}
}

void Init(int A, int B) {
	::A = A;
	::B = B;
	type = B>0;
	Solve1::pst=1;
	Solve2::dirc=0;
	Solve2::S.clear();
	Solve2::pst=-1;
}

int Move(std::vector<int> y) {
	if(!type){
		return Solve1::Do(y);
	}else {
		return Solve2::Do(y);
	}
	return -1;
}
posted @ 2020-03-24 20:28  jerome_wei  阅读(321)  评论(0编辑  收藏  举报