nocriz的博客

苔花如米小,也学牡丹开。

杭电多校第九场-1010-Jump

这场比赛是我们队回到西安之后打的第1场多校比赛。这场比赛难度比较大,题目好像我也没怎么补。所以做了5题就拿到了第2名,第1名好像有6题,然后后面的队就都是4题对。这场比赛我发挥的不错,最后的两道题都是我做的。其中一道就是这一道只有一个人过的1010。

题意:有一棵树,边有边权。你现在维护一个点的序列,操作有两种: 1.将[l,r]区间中所有点都变为其父节点(根的父节点为根节点)2.查询[l,r]区间中所有点的深度最小值

考虑sqrt分块,则我们需要处理四种操作:

1.整块变为父节点
2.块中部分节点变为父节点
3.整块询问
4.部分节点询问

我们先考虑只有1、3、4操作的情形。我们考虑建立块中所有节点的虚树,有祖先节点也在块中的节点则是永远不会成为深度最小的点的。我们去掉这些点,就得到了只有叶子节点是块中节点的一颗虚树。维护这些节点,每次操作1时都将所有点暴力变为父节点,并检查此时是否有节点是其他节点的祖先节点,及时删除没有用的节点。

由于每一个节点只会变成其父节点一次,每个块总的操作次数将不超过n。如果在更新时候维护答案,就可以直接回答3类操作。我们记录整个块被操作1进行了几次,并使用某些寻找每个节点的k祖先的方法就可以回答4类操作。

考虑2类操作,可以每次暴力重构。

事实上,不需要显式地建立虚树,只需要把有可能成为答案的点按照dfs序排序存在vector里面即可。由于将所有节点变为父节点,dfs序的相对顺序改变是有限的,因此可以线性进行这样的操作。下面是将一个这样的vector全部变为其父节点的函数的线性实现:

vector<int> cns(vector<int> Fr){
        sort(all(Fr),cmp);
        vector<int> nxt;
        for(auto ct:Fr){
            if(!nxt.size()){
                nxt.PB(ct);
                continue;
            }
            if(!subtree(nxt.back(),ct))nxt.PB(ct);
        }
        return nxt;
    }

我使用的找到祖先节点的方法是倍增,因此复杂度是n sqrt(n log n)的?如果改成O(1)的方法,可能可以达到n sqrt n,但是我没试过。

题解给出的做法如下,和我的做法并不相同,复杂度好像和我差不多。

首先我们回顾一下一个事实,就是如果我们每次删除当前树上所有度数为1的点,那么经过O(T)轮之 后,树上的度数为1的点不会超过O(n/ T) 个,我们记这些点为关键点,那么可以发现,如果一个点往上 跳了O(T)轮,那么一定在某个关键点之上,而一个关键点之上的点在一条链上,那么最浅点很容易维 护。
所以算法大致上是这样的,首先每个点到关键点之前的这一段,我们暴力跳。之后我们对于每个关键点 分别最浅的点,等价于区间减,区间最小值。
前面部分需要做O(nT) 次单点修改,O(n)次区间查询,而后面部分需要做O \left(n^{2} / T\right) 次修改和查询,这 里我们假设 n, q 同阶。前面部分可以用分块将复杂度平衡成为 O(n T)+O\left(n^{1.5}\right), 后面部分时间复杂度 为 O\left(n^{2} \log n / T\right), 所以总的时间复杂度为 O(n \sqrt{n \log n})

代码如下。

#include <bits/stdc++.h>
using namespace std;

template <typename A, typename B>string to_string(pair<A, B> p);template <typename A, typename B, typename C>string to_string(tuple<A, B, C> p);template <typename A, typename B, typename C, typename D>string to_string(tuple<A, B, C, D> p);string to_string(const string& s) {  return '"' + s + '"';}string to_string(const char* s) {  return to_string((string) s);}string to_string(bool b) {  return (b ? "true" : "false");}string to_string(vector<bool> v) {  bool first = true;  string res = "{";  for (int i = 0; i < static_cast<int>(v.size()); i++) {    if (!first) {      res += ", ";    }    first = false;    res += to_string(v[i]);  }  res += "}";  return res;}template <size_t N>string to_string(bitset<N> v) {  string res = "";  for (size_t i = 0; i < N; i++) {    res += static_cast<char>('0' + v[i]);  }  return res;}template <typename A>string to_string(A v) {  bool first = true;  string res = "{";  for (const auto &x : v) {    if (!first) {      res += ", ";    }    first = false;    res += to_string(x);  }  res += "}";  return res;}template <typename A, typename B>string to_string(pair<A, B> p) {  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";}template <typename A, typename B, typename C>string to_string(tuple<A, B, C> p) {  return "(" + to_string(get<0>(p)) + ", " + to_string(get<1>(p)) + ", " + to_string(get<2>(p)) + ")";}template <typename A, typename B, typename C, typename D>string to_string(tuple<A, B, C, D> p) {  return "(" + to_string(get<0>(p)) + ", " + to_string(get<1>(p)) + ", " + to_string(get<2>(p)) + ", " + to_string(get<3>(p)) + ")";}void debug_out() { cerr << endl; }template <typename Head, typename... Tail>void debug_out(Head H, Tail... T) {  cerr << " " << to_string(H);  debug_out(T...);}

#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

#define set0(x) memset(x,0,sizeof(x))
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
template<typename T> void read(T &x){
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
    read(first);
    read(args...);
}

int T,n,m,rt,u,v,d,opt,l,r;
int val[450020],dfn[450020],sz[450020],d1[450020],ff[450020][20];
ll d2[450020];

vector<pii> G[450020];

int tim;
void dfs(int num,int fa = -1){
    ff[num][0] = fa;if(fa == -1)ff[num][0] = num;
    for(int i=1;i<20;i++) ff[num][i] = ff[ff[num][i-1]][i-1];
    tim+=1;
    sz[num] = 1;
    dfn[num] = tim;
    for(auto ct:G[num]){
        if(ct.F == fa)continue;
        d1[ct.F] = d1[num]+1;
        d2[ct.F] = d2[num]+ct.S;
        dfs(ct.F,num);
        sz[num]+=sz[ct.F];
    }
}
inline bool subtree(int a,int b){
    return dfn[b]<dfn[a]+sz[a] && dfn[b]>=dfn[a];
}
bool cmp(int a,int b){
    return dfn[a]<dfn[b];
}
struct block{
    int l = 1e9,r = -1,up = 0,changed = 1;
    ll cache = 0;
    vector<int> A,sig;
    vector<int> cns(vector<int> Fr){
        sort(all(Fr),cmp);
        vector<int> nxt;
        for(auto ct:Fr){
            if(!nxt.size()){
                nxt.PB(ct);
                continue;
            }
            if(!subtree(nxt.back(),ct))nxt.PB(ct);
        }
        return nxt;
    }
    void construct(){
        sig = cns(A);
    }
    void solve1(int opl,int opr){
        if(opr<l || opl>r)return;
        changed = 1;
        if(opl<=l && r<=opr){
            vector<int> nxt;
            for(auto ct:sig){
                int cc = ff[ct][0];
                if(!nxt.size()){
                    nxt.PB(cc);
                    continue;
                }
                if(subtree(nxt.back(),cc))continue;
                while(nxt.size() && subtree(cc,nxt.back()))nxt.pop_back();
                nxt.PB(cc);
            }
            sig = nxt;
            up+=1;
        }else{
            if(up){
                for(int i=0;i<18;i++){
                    if((up>>i)&1){
                        for(int j=0;j<A.size();j++)A[j] = ff[A[j]][i];
                    }
                }
                up = 0;
            }
            for(int i= max(opl,l);i<=min(opr,r);i++){
                A[i-l] = ff[A[i-l]][0];
            }
            construct();
        }
    }
    ll solve2(int opl,int opr){
        ll ans = 1e18;
        if(opr<l || opl>r)return ans;
        if(opl<=l && r<=opr){
            if(!changed)return cache;
            for(auto ct:sig)ans = min(ans,d2[ct]);
            cache = ans;
            changed = 0;
        }else{
            for(int i=0;i<18;i++){
                if((up>>i)&1){
                    for(int j=0;j<A.size();j++)A[j] = ff[A[j]][i];
                }
            }
            up = 0;
            for(int i= max(opl,l);i<=min(opr,r);i++){
                ans = min(ans,d2[A[i-l]]);
            }
        }
        return ans;
    }
};

int main() {
    read(T);
    while(T--){
        tim = 1;
        read(n,m,rt);
        d2[rt] = d1[rt] = 0;
        for(int i=0;i<n-1;i++){
            read(u,v,d);
            G[u].PB(MP(v,d));
            G[v].PB(MP(u,d));
        }
        vector<block> blocks(1010);
        for(int i=1;i<=n;i++){
            read(val[i]);
            blocks[i/300].r = max(blocks[i/300].r,i);
            blocks[i/300].l = min(blocks[i/300].l,i);
            blocks[i/300].A.PB(val[i]);
        }
        dfs(rt);
        for(auto &ct:blocks)ct.construct();
        for(int i=1;i<=m;i++){
            read(opt,l,r);
            if(opt == 1){
                for(int j=l/300;j<=r/300;j++)blocks[j].solve1(l,r);
            }else{
                ll ans = 1e18;
                for(int j=l/300;j<=r/300;j++)ans = min(ans,blocks[j].solve2(l,r));
                cout<<ans<<"\n";
            }
        }
        for(int i=0;i<n+10;i++){
            G[i].clear();
        }
    }
    return 0;
}

评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注