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;
}