题目
n(n<=2e5)个点的一棵树,你需要将n个点的权值构造为一个[1,n]的排列,
并满足m(m<=2e5)个限制,限制分两种:
1 a b c,要求点a到点b的简单路径上,最小值位于点c处,保证c在a到b的简单路径上
2 a b c,要求点a到点b的简单路径上,最大值位于点c处,保证c在a到b的简单路径上
不能构造输出-1
思路来源
SSerxhs代码、官方题解代码
线段树优化建图
题解
感觉很典,就是三个板子拼到了一起的这么一个题
有大小关系限制,考虑拓扑排序,x->y连一条边,表示x需要小于y
考虑怎么暴力,暴力就是将链上的每个点i都和c之间连边,
c是最小值的话,c->i连边;
c是最大值的话,i->c连边
然后考虑怎么优化点的数量,
这就是线段树优化区间建图的思想,一棵入树,一棵出树,
c最小值的话,就在出树(自顶向下)上连;
c是最大值的话,就在入树(自底向上)上连
如果用树链剖分做的话,由于树链上是log条重链和轻点,每条链dfs序连续,
可以用现成的线段树优化区间建图的板子,每棵树的点的总数是4n
一条链可以映射到log个点上,每个限制连接log^2个点,最后对所有限制跑一遍拓扑排序即可
有环肯定无解,否则输出任意拓扑序即可
然后如果用倍增做的话,每个点往上跳2^i步认为是一个点,
2^i步的点连着2^(i-1)步的两个点,也是一棵入树、一棵出树,每棵树的点的总数是nlogn
点更多了,只是这样边更少,每个限制连接log个点
复杂度:树剖O((n+m)log^2),倍增O((n+m)log),
但是实践意义上看起来树剖跑得比较快…
懒得写代码了直接复制了
代码1(树链剖分,SSerxhs)
#include "bits/stdc++.h"
using namespace std;
template<typename T1,typename T2> istream &operator>>(istream &cin,pair<T1,T2> &a) { return cin>>a.first>>a.second; }
template<typename T1> istream &operator>>(istream &cin,vector<T1> &a) { for (auto &x:a) cin>>x; return cin; }
template<typename T1> istream &operator>>(istream &cin,valarray<T1> &a) { for (auto &x:a) cin>>x; return cin; }
template<typename T1,typename T2> ostream &operator<<(ostream &cout,const pair<T1,T2> &a) { return cout<<a.first<<' '<<a.second; }
template<typename T1,typename T2> ostream &operator<<(ostream &cout,const vector<pair<T1,T2>> &a) { for (auto &x:a) cout<<x<<'\n'; return cout; }
template<typename T1> ostream &operator<<(ostream &cout,const vector<T1> &a) { int n=a.size(); if (!n) return cout; cout<<a[0]; for (int i=1; i<n; i++) cout<<' '<<a[i]; return cout; }
template<typename T1,typename T2> bool cmin(T1 &x,const T2 &y) { if (y<x) { x=y; return 1; } return 0; }
template<typename T1,typename T2> bool cmax(T1 &x,const T2 &y) { if (x<y) { x=y; return 1; } return 0; }
template<typename T1> vector<T1> range(T1 l,T1 r,T1 step=1) { assert(step>0); int n=(r-l+step-1)/step,i; vector<T1> res(n); for (i=0; i<n; i++) res[i]=l+step*i; return res; }
template<typename T1> basic_string<T1> operator*(const basic_string<T1> &s,int m) { auto r=s; m*=s.size(); r.resize(m); for (int i=s.size(); i<m; i++) r[i]=r[i-s.size()]; return r; }
#if !defined(ONLINE_JUDGE)&&defined(LOCAL)
#include "my_header\debug.h"
#else
#define dbg(...) ;
#define dbgn(...) ;
#endif
typedef unsigned int ui;
typedef double db;
typedef long long ll;
#define all(x) (x).begin(),(x).end()
// template<typename T1,typename T2> void inc(T1 &x,const T2 &y) { if ((x+=y)>=p) x-=p; }
// template<typename T1,typename T2> void dec(T1 &x,const T2 &y) { if ((x+=p-y)>=p) x-=p; }
namespace HLD
{
const int N=2e5+2;
vector<int> e[N];
int dfn[N],nfd[N],dep[N],f[N],siz[N],hc[N],top[N];
int id;
void dfs1(int u)
{
siz[u]=1;
for (int v:e[u]) if (v!=f[u])
{
dep[v]=dep[f[v]=u]+1;
dfs1(v);
siz[u]+=siz[v];
if (siz[v]>siz[hc[u]]) hc[u]=v;
}
}
void dfs2(int u)
{
dfn[u]=++id;
nfd[id]=u;
if (hc[u])
{
top[hc[u]]=top[u];
dfs2(hc[u]);
for (int v:e[u]) if (v!=hc[u]&&v!=f[u]) dfs2(top[v]=v);
}
}
int lca(int u,int v)
{
while (top[u]!=top[v])
{
if (dep[top[u]]<dep[top[v]]) swap(u,v);
u=f[top[u]];
}
if (dep[u]>dep[v]) swap(u,v);
return u;
}
int dis(int u,int v)
{
return dep[u]+dep[v]-(dep[lca(u,v)]<<1);
}
void init(int n)
{
for (int i=1; i<=n; i++)
{
e[i].clear();
f[i]=hc[i]=0;
}
id=0;
}
void fun(int root)
{
dep[root]=1; dfs1(root); dfs2(top[root]=root);
}
vector<pair<int,int>> get_path(int u,int v)//u->v,注意可能出现 [r>l](表示反过来走)
{
//cerr<<"path from "<<u<<" to "<<v<<": ";
vector<pair<int,int>> v1,v2;
while (top[u]!=top[v])
{
if (dep[top[u]]>dep[top[v]]) v1.push_back({dfn[u],dfn[top[u]]}),u=f[top[u]];
else v2.push_back({dfn[top[v]],dfn[v]}),v=f[top[v]];
}
v1.reserve(v1.size()+v2.size()+1);
v1.push_back({dfn[u],dfn[v]});
reverse(v2.begin(),v2.end());
for (auto v:v2) v1.push_back(v);
//for (auto [x,y]:v1) cerr<<"["<<x<<','<<y<<"] ";cerr<<endl;
return v1;
}
}
using HLD::lca,HLD::dis,HLD::dfn,HLD::nfd,HLD::dep,HLD::f,HLD::siz,HLD::get_path;
using HLD::fun,HLD::init;//5e5
const int N=2e5+5;
vector<int> e[N*7];
int in[N*4],out[N*4],deg[N*7],ans[N];
int id,z,y,ver;
void add(int u,int v)
{
// cerr<<u<<' '<<v<<endl;
e[u].push_back(v);
++deg[v];
}
void build(int x,int l,int r)
{
if (l==r)
{
in[x]=out[x]=l;
return;
}
int c=x*2,m=l+r>>1;
build(c,l,m); build(c+1,m+1,r);
in[x]=++id; out[x]=++id;
add(in[x],in[c]);
add(in[x],in[c+1]);
add(out[c],out[x]);
add(out[c+1],out[x]);
}
void addin(int x,int l,int r)
{
if (z<=l&&r<=y)
{
add(ver,in[x]);
return;
}
int c=x*2,m=l+r>>1;
if (z<=m) addin(c,l,m);
if (y>m) addin(c+1,m+1,r);
}
void addout(int x,int l,int r)
{
if (z<=l&&r<=y)
{
add(out[x],ver);
return;
}
int c=x*2,m=l+r>>1;
if (z<=m) addout(c,l,m);
if (y>m) addout(c+1,m+1,r);
}
int main()
{
ios::sync_with_stdio(0); cin.tie(0);
cout<<fixed<<setprecision(15);
int n,m,i,j;
cin>>n>>m;
id=n;
init(n);
for (i=1; i<n; i++)
{
int u,v;
cin>>u>>v;
HLD::e[u].push_back(v);
HLD::e[v].push_back(u);
}
fun(1);
build(1,1,n);
while (m--)
{
int t,a,b,c;
cin>>t>>a>>b>>c;
if (dis(a,b)!=dis(b,c)+dis(a,c))
{
cout<<-1<<endl;
return 0;
}
auto v=get_path(a,b);
ver=dfn[c];
if (t==1)
{
for (auto [l,r]:v)
{
if (l>r) swap(l,r);
if (l<=ver&&ver<=r)
{
z=l; y=ver-1;
if (z<=y) addin(1,1,n);
z=ver+1; y=r;
if (z<=y) addin(1,1,n);
continue;
}
z=l; y=r;
addin(1,1,n);
}
}
else
{
for (auto [l,r]:v)
{
if (l>r) swap(l,r);
if (l<=ver&&ver<=r)
{
z=l; y=ver-1;
if (z<=y) addout(1,1,n);
z=ver+1; y=r;
if (z<=y) addout(1,1,n);
continue;
}
z=l; y=r;
addout(1,1,n);
}
}
}
queue<int> q;
for (i=1; i<=id; i++) if (!deg[i]) q.push(i);
id=0;
while (q.size())
{
int u=q.front(); q.pop();
if (u<=n) ans[nfd[u]]=++id;
for (int v:e[u]) if (!--deg[v]) q.push(v);
}
if (id!=n)
{
cout<<-1<<endl;
return 0;
}
for (i=1; i<=n; i++) cout<<ans[i]<<" \n"[i==n];
}
代码2(倍增,官方题解)
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,avx2,fma")
#pragma GCC target("sse4,popcnt,abm,mmx,tune=native")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define ff first
#define ss second
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ld, ld> pld;
const int INF = 1e9;
const ll LLINF = 1e18;
const int MOD = 1e9 + 7;
template<class K> using sset = tree<K, null_type, less<K>, rb_tree_tag, tree_order_statistics_node_update>;
inline ll ceil0(ll a, ll b) {
return a / b + ((a ^ b) > 0 && a % b);
}
void setIO() {
ios_base::sync_with_stdio(0); cin.tie(0);
}
const int MAXN = 200'000;
const int LG = 18;
const int MAXM = 200'000;
vector<int> g[MAXN + 5];
int sz[MAXN + 5], in[MAXN + 5], par[MAXN + 5], depth[MAXN + 5], head[MAXN + 5], tim;
int n, m;
void dfs1(int x, int p){
sz[x] = 1;
for(int &i : g[x]){
if(i == p) continue;
dfs1(i, x);
sz[x] += sz[i];
if(g[x][0] == p || sz[i] > sz[g[x][0]]) swap(g[x][0], i);
}
}
void dfs2(int x, int p){
in[x] = tim++;
par[x] = p;
depth[x] = depth[p] + 1;
for(int i : g[x]){
if(i == p) continue;
head[i] = (i == g[x][0] ? head[x] : i);
dfs2(i, x);
}
}
const int MAXSZ = MAXN + 2*MAXN*LG;
int down[LG][MAXN + 5];
int up[LG][MAXN + 5];
vector<int> dag[MAXSZ+ 5];
int lg[MAXN + 5];
void upd(int l, int r, int x, int t){
if(l <= in[x] && in[x] <= r){
if(l < in[x]) upd(l, in[x] - 1, x, t);
if(in[x] < r) upd(in[x] + 1, r, x, t);
} else {
int sz = lg[r - l + 1];
if(t == 2){
dag[up[sz][l]].pb(x);
dag[up[sz][r - (1 << sz) + 1]].pb(x);
} else {
dag[x].pb(down[sz][l]);
dag[x].pb(down[sz][r - (1 << sz) + 1]);
}
}
}
//1 is down, 2 is up
void draw(int a, int b, int c, int t){
while(head[a] != head[b]){
if(depth[head[a]] > depth[head[b]]) swap(a, b);
upd(in[head[b]], in[b], c, t);
b = par[head[b]];
}
if(depth[a] > depth[b]) swap(a, b);
upd(in[a], in[b], c, t);
}
bool vis[MAXSZ + 5], stk[MAXSZ + 5];
vector<int> ord;
bool fail;
int ind;
void dfs3(int x){
if(fail) return;
vis[x] = stk[x] = true;
for(int i : dag[x]){
if(i == x) continue;
if(!vis[i]){
dfs3(i);
} else if(stk[i]){
fail = true;
break;
}
}
stk[x] = false;
if(x <= n) ord.pb(x);
}
int main(){
setIO();
cin >> n >> m;
lg[1] = 0;
for(int i = 2; i <= n; i++) lg[i] = lg[i/2] + 1;
for(int i = 0; i < n - 1; i++){
int a, b;
cin >> a >> b;
g[a].pb(b);
g[b].pb(a);
}
tim = 0;
dfs1(1, 1);
head[1] = 1;
dfs2(1, 1);
for(int i = 1; i <= n; i++) down[0][in[i]] = up[0][in[i]] = i;
ind = n + 1;
for(int i = 1; i < LG; i++){
for(int j = 0; j + (1 << i) <= n; j++){
down[i][j] = ind++;
up[i][j] = ind++;
dag[down[i][j]].pb(down[i - 1][j]);
dag[down[i][j]].pb(down[i - 1][j + (1 << (i - 1))]);
dag[up[i - 1][j]].pb(up[i][j]);
dag[up[i - 1][j + (1 << (i - 1))]].pb(up[i][j]);
}
}
for(int i = 0; i < m; i++){
int t, a, b, c;
cin >> t >> a >> b >> c;
draw(a, b, c, t);
}
fail = false;
for(int i = 1; i <= n; i++){
if(!vis[i]){
dfs3(i);
if(fail) break;
}
}
if(fail){
cout << -1 << endl;
return 0;
}
reverse(ord.begin(), ord.end());
int ans[n + 1];
for(int i = 0; i < ord.size(); i++){
ans[ord[i]] = i + 1;
}
for(int i = 1; i <= n; i++) cout << ans[i] << " ";
cout << endl;
}