8.10 数据结构+树论
P4197 Peaks
和永无乡相差不多()
先将高度离散化 将所有的边以边权为关键字排序
将所有的询问离线 以\(x\)为关键字排序 每一次查询加入一批权值小于等于\(x\)的边
为每一个连通块维护一个主席树 用并查集合并联通块 注意必须要把子节点合并到父节点上 且并查集必须初始化
每次查询的时候 我们查询这个连通块的根节点的主席树中第\(k\)大即可 注意是第\(k\)大
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls(p) t[p].son[0]
#define rs(p) t[p].son[1]
#define lson ls(p),l,mid
#define rson rs(p),mid+1,r
#define pii pair<int,int>
const int N = 5e5 + 5;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , q , now = 1 , ans[N] , rt[N] , a[N];
int fa[N];
int find ( int x ) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
vector<int> lsh;
struct edge { int u , v , w; } e[N];
struct que { int u , x , k , i; };
vector<que> qq;
struct Tree
{
struct node { int son[2] , sz; } t[100000*32];
int tot = 0;
inl void up ( int p ) { t[p].sz = t[ls(p)].sz + t[rs(p)].sz; }
void upd ( int &p , int l , int r , int x )
{
if ( !p ) p = ++tot; t[p].sz ++;
if ( l == r ) return;
if ( x <= mid ) upd ( lson , x );
else upd ( rson , x );
}
void merge ( int &p , int l , int r , int u , int v )
{
if ( !u || !v ) return p = u + v , void();
if ( l == r ) return t[p].sz = t[u].sz + t[v].sz , void();
merge ( lson , ls(u) , ls(v) ) , merge ( rson , rs(u) , rs(v) ) , up(p);
}
int query ( int p , int l , int r , int k )
{
if ( t[p].sz < k ) return 0;
if ( l == r ) return l;
if ( t[rs(p)].sz >= k ) return query ( rson , k );
else return query ( lson , k - t[rs(p)].sz );
}
}T;
void merge ( int u , int v )
{
int fu = find(u) , fv = find(v);
if ( fu == fv ) return;
fa[fu] = fv;
T.merge ( rt[fv] , 1 , n , rt[fu] , rt[fv] );
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read() , q = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , lsh.eb(a[i]) , fa[i] = i;
sort ( lsh.begin() , lsh.end() );
lsh.erase ( unique ( lsh.begin() , lsh.end() ) , lsh.end() );
for ( int i = 1 ; i <= n ; i ++ ) a[i] = lower_bound ( lsh.begin() , lsh.end() , a[i] ) - lsh.begin() + 1 , T.upd ( rt[i] , 1 , lsh.size() , a[i] );
n = lsh.size();
for ( int i = 1 ; i <= m ; i ++ ) e[i].u = read() , e[i].v = read() , e[i].w = read();
sort ( e + 1 , e + m + 1 , [](const edge &a , const edge &b) { return a.w < b.w; } );
for ( int i = 1 , u , x , k ; i <= q ; i ++ ) u = read() , x = read() , k = read() , qq.eb((que){u,x,k,i});
sort ( qq.begin() , qq.end() , [](const que &a , const que &b) { return a.x < b.x; } );
for ( auto [u,x,k,id] : qq )
{
while ( now <= m && e[now].w <= x ) merge ( e[now].u , e[now].v ) , now ++;
int pos = T.query ( rt[find(u)] , 1 , n , k );
if ( pos == 0 ) ans[id] = -1;
else ans[id] = lsh[pos-1];
}
for ( int i = 1 ; i <= q ; i ++ ) cout << ans[i] << endl;
return 0;
}
P4981 父子
一个结论:一棵\(n\)个点的无根树 树的形态个数为\(n^{n-2}\)种 又因为树是有根的 所以我们需要再乘上一个\(n\)
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define int long long
const int mod = 1e9 + 9;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int ksm ( int base , int k )
{
int res = 1;
for ( ; k ; ( base *= base ) %= mod , k >>= 1 )
if ( k & 1 ) ( res *= base ) %= mod;
return res;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
int n = read();
cout << ksm ( n , n - 1 ) << endl;
}
return 0;
}
P2680 [NOIP2015 提高组] 运输计划
第二次打()感觉第一遍没有掌握明白
\(LCA\)+树上差分+二分答案+点权转边权
考虑二分这个最短时间 考虑如何\(check()\)
我们预处理每一次询问的链的长度 那么这个长度如果大于\(mid\) 就将这条链在树上做一次差分标记 最后再\(dfs\)一次来统计
如果存在一条边 使得这条边经过所有的链 而且原来所有链长的最大值\(maxx\)减去这条边的长度 都小于等于\(mid\) 那么是合法的
这次用了更好理解的树中\(dfs\)写法 不过常数大了三倍不止()
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define int long long
const int mod = 1e9 + 9;
const int N = 3e5 + 5;
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
// #define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , lca[N] , u[N] , v[N] , d[N] , maxx , pass[N];
int fa[N] , sz[N] , dep[N] , son[N] , dis[N] , a[N];
int timer , rev[N] , pos[N] , top[N];
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
struct LCA
{
void dfs1 ( int u , int f )
{
fa[u] = f , dep[u] = dep[f] + 1 , sz[u] = 1;
for ( auto [v,w] : e[u] )
if ( v ^ f )
{
a[v] = w , dis[v] = dis[u] + w;
dfs1 ( v , u );
sz[u] += sz[v];
if ( sz[son[u]] < sz[v] ) son[u] = v;
}
}
void dfs2 ( int u , int tp )
{
top[u] = tp , pos[u] = ++timer , rev[timer] = u;
if ( son[u] ) dfs2 ( son[u] , tp );
for ( auto [v,w] : e[u] ) if ( v ^ fa[u] && v ^ son[u] ) dfs2 ( v , v );
}
int lca ( int u , int v )
{
while ( top[u] != top[v] )
{
if ( dep[top[u]] < dep[top[v]] ) swap ( u , v );
u = fa[top[u]];
}
if ( dep[u] < dep[v] ) swap ( u , v );
return v;
}
}L;
void dfs ( int u , int f ) { for ( auto [v,w] : e[u] ) if ( v ^ f ) dfs ( v , u ) , pass[u] += pass[v]; }
int check ( int x )
{
int tot = 0;
for ( int i = 1 ; i <= n ; i ++ ) pass[i] = 0;
for ( int i = 1 ; i <= m ; i ++ ) if ( x < d[i] ) tot ++ , pass[u[i]] ++ , pass[v[i]] ++ , pass[lca[i]] -= 2;
dfs ( 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) if ( maxx - a[i] <= x && pass[i] == tot ) return 1;
return 0;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read();
for ( int i = 1 , u , v , w ; i < n ; i ++ ) u = read() , v = read() , w = read() , add ( u , v , w ) , add ( v , u , w );
L.dfs1 ( 1 , 0 ) , L.dfs2 ( 1 , 1 );
for ( int i = 1 ; i <= m ; i ++ )
{
u[i] = read() , v[i] = read() , lca[i] = L.lca ( u[i] , v[i] );
d[i] = dis[u[i]] + dis[v[i]] - 2 * dis[lca[i]];
maxx = max ( maxx , d[i] );
}
int l = 0 , r = maxx;
while ( l <= r )
{
if ( check(mid) ) r = mid - 1;
else l = mid + 1;
}
cout << l << endl;
return 0;
}
P3459 [POI2007] MEG-Megalopolis
\(dfn\)序+线段树
我们先对于每一个点进行\(dfs\) 为他们赋一个\(dfn\)序
之后按照\(dfn\)序建树 树中节点初始值赋为初始深度\(dep\)
对于每一次修路\((u,v)\) 影响的值就是\(v\)子树内到根节点的路径需要减一 又因为\(dfn\)序是连续的 那么直接线段树区间修改即可
查询的时候直接单点查询\(dfn[u]\)即可
错误:查询的时候查了\(u\)而不是\(dfn[u]\)
(实际上这道题显然也可以树剖 代码见树剖练习题)
#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
const int N = 5e5 + 5;
// char buf[1<<24] , *p1 , *p2;
// #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
#define getchar() cin.get();
int read()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f ;
}
int n , m , dep[N] , rev[N] , sz[N];
int dfn[N] , timer;
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
void dfs ( int u , int f )
{
dfn[u] = ++timer , rev[timer] = u , dep[u] = dep[f] + 1 , sz[u] = 1;
for ( auto v : e[u] ) if ( v ^ f ) dfs ( v , u ) , sz[u] += sz[v];
}
struct segtree
{
struct node { int sum , add; } t[N<<2];
inl void up ( int p ) { t[p].sum = t[ls].sum + t[rs].sum; }
inl void pushadd ( int p , int l , int r , int val ) { t[p].sum += ( r - l + 1 ) * val , t[p].add += val; }
inl void down ( int p , int l , int r ) { if ( t[p].add ) pushadd ( lson , t[p].add ) , pushadd ( rson , t[p].add ) , t[p].add = 0; }
void build ( int p , int l , int r )
{
if ( l == r ) return t[p].sum = dep[rev[l]] , void();
build ( lson ) , build ( rson ) , up(p);
}
void upd ( int p , int l , int r , int x , int y , int val )
{
if ( x <= l && r <= y ) return pushadd ( p , l , r , val ) , void();
down(p,l,r);
if ( x <= mid ) upd ( lson , x , y , val );
if ( mid + 1 <= y ) upd ( rson , x , y , val );
up(p);
}
int query ( int p , int l , int r , int x )
{
if ( l == r ) return t[p].sum;
down(p,l,r);
if ( x <= mid ) return query ( lson , x );
else return query ( rson , x );
}
}T;
char ch;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
m = read();
dep[0] = -1 , dfs ( 1 , 0 ) , T.build ( 1 , 1 , n );
for ( int i = 1 , u , v ; i <= n + m - 1 ; i ++ )
{
cin >> ch;
if ( ch == 'A' ) { u = read() , v = read() , T.upd ( 1 , 1 , n , dfn[v] , dfn[v] + sz[v] - 1 , -1 ); }
else u = read() , cout << T.query ( 1 , 1 , n , dfn[u] ) << endl;//dfn[u]不要写成u了!
}
return 0;
}