18寒假第三测

Posted Ed_Sheeran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了18寒假第三测相关的知识,希望对你有一定的参考价值。

第一题:找LCA,两点之间的距离=他们各自到起点的距离 - 2*LCA到起点的距离

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100015, P = 20;


int head[2 * maxn],to[2 * maxn],last[2 *maxn],co[2 * maxn],dep[maxn], idx, anc[maxn][P+1],dis[maxn];
void dfs(int u,int from){
    //in[u] = ++idx;    
    anc[u][0] = from;
    for(int p = 1; p <= P; p++)
        anc[u][p] = anc[anc[u][p-1]][p-1];
    for(int i = head[u]; i; i = last[i]){
        if(to[i] != from){
            dep[to[i]] = dep[u] + 1;
            dis[to[i]] = dis[u] + co[i];
            dfs(to[i], u);
        }
    }
}
void adde(int u,int v,int w){
    idx++;
    last[idx] = head[u];
    to[idx] = v;    
    co[idx] = w;
    head[u] = idx;
}
int lca(int u,int v){
    if(dep[u] < dep[v])swap(u, v);
    int t = dep[u] - dep[v];
    for(int p = 0; t; t >>= 1, p++)
        if(t & 1)u = anc[u][p];
    if(u == v)return v;
    
    for(int p = P; p >=0; p--)
        if(anc[u][p] != anc[v][p])
            u = anc[u][p], v = anc[v][p];
    return anc[u][0];
}
int main(){
    freopen ( "distance.in", "r", stdin ) ;
    freopen ( "distance.out", "w", stdout ) ;
    int n,m;
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        adde( u, v, w );
        adde( v, u, w );
    }
    
    dfs(1,1);
    cin>>m;
    for(int i=1;i<=m;i++){
        int u ,v;
        scanf("%d%d",&u,&v);
        int q = lca(u,v);
        printf("%d\\n",dis[v]+dis[u]-dis[q]*2);
    }
    
    
    
}

第二题:先dfs的dfn序,再投影得到一个序列,建线段树

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

const int oo = 0x3f3f3f3f;

#define MAX_N 100005
long long sum ;
int head[MAX_N<<1],next[MAX_N<<1],to[MAX_N<<1];
int tot, a[MAX_N], in[MAX_N], out[MAX_N],dep[MAX_N],n, m, idx;
void dfs(int u,int from){
    in[u] = ++idx;
    for(int i = head[u]; i; i = next[i]){
        int v = to[i];
        if(v != from){
            dep[v] = dep[u] + 1;
            dfs(v,u);
        }
    }
    out[u] = idx;
}

void adde(int u,int v){
    ++tot;
    next[tot] = head[u];
    to[tot] = v;
    head[u] = tot;
        
}

struct SegTree{
    struct node{
        long long sum;
        int vmin,vmax,lazy;
    };
    node Tree[MAX_N << 2];
    
    #define ls l, m, v << 1
    #define rs m+1, r, v << 1 | 1
    void push_up(int v){
        Tree[v].sum = Tree[v << 1].sum + Tree[v << 1 | 1].sum;
        Tree[v].vmin = min(Tree[v << 1].vmin, Tree[v << 1 | 1].vmin);
        Tree[v].vmax = max(Tree[v << 1].vmax, Tree[v << 1 | 1].vmax);    
    }
    void push_down(int l, int r, int v){
        int m = (l + r) >> 1;
        
        Tree[v << 1].sum += 1LL * Tree[v].lazy * (m - l +1);
        Tree[v << 1].vmin += Tree[v].lazy;
        Tree[v << 1].vmax += Tree[v].lazy;
        Tree[v << 1].lazy += Tree[v].lazy;
        
        Tree[v << 1 | 1].sum += 1LL * Tree[v].lazy * (r - m);
        Tree[v << 1 | 1].vmin += Tree[v].lazy;
        Tree[v << 1 | 1].vmax += Tree[v].lazy;
        Tree[v << 1 | 1].lazy += Tree[v].lazy;
        
        Tree[v].lazy = 0;
    }    
    void modify(int x,int L,int R,int l = 1, int r = n, int v = 1){
        if(l >= L && r <= R){
            Tree[v].lazy += x;
            Tree[v].sum += 1LL * x * (r - l + 1);
            Tree[v].vmin += x;
            Tree[v].vmax += x;            
        }
        else {
            if(Tree[v].lazy)push_down(l,r,v);
            int m = (l + r) / 2;
            if(L <= m)modify(x,L,R,ls);
            if(R > m)modify(x,L,R,rs);
            push_up(v);            
        }    
    }
    
    node query(int L,int R,int l = 1, int r = n,int v = 1){
        if(l >= L && r <= R)
            return Tree[v];
        else {
            if(Tree[v].lazy) push_down(l,r,v);
            int m = (l + r) / 2;
            node ans;
            ans.vmin = oo, ans.vmax = -oo, ans.sum = 0;
            if(L <= m){
                node nw = query(L,R,ls);
                ans.vmin = min(ans.vmin, nw.vmin);
                ans.vmax = max(ans.vmax, nw.vmax);
                ans.sum += nw.sum;
            }
            if(R > m){
                node nw = query(L,R,rs);
                ans.vmin = min(ans.vmin, nw.vmin);
                ans.vmax = max(ans.vmax, nw.vmax);
                ans.sum += nw.sum;
            }
            return ans;
        }
    }
};

SegTree Tr;
int main(){
    freopen("redpacket.in","r",stdin);
    freopen("redpacket.out","w",stdout);
    cin>>n;
    for(int i = 1; i < n; i++){
        int u,v;
        scanf("%d%d",&u,&v);
        adde(u,v);
        adde(v,u);
    }
        
    dep[1] = 1;
    dfs(1,1);
//    Tr.build();
    cin>>m;
    for(int i = 1; i <= m; i++){
        string opt;
        cin>>opt;
        if(opt[0] == \'a\'){
            int u;
            scanf("%d",&u);
            SegTree::node nw;
            nw = Tr.query(in[u],out[u]);
            cout<<nw.sum<<endl;
        }
        else if(opt[0] == \'g\'){
            int u, x;
            scanf("%d%d",&u,&x);
            Tr.    modify(x,in[u],out[u]);
        }
        else {
            int u;
            scanf("%d",&u);
            SegTree::node nw;
            nw = Tr.query(in[u],in[u]);
            cout<<nw.sum<<endl;
        }
    }
}

 

第三题:比如这条红链上+5,在两个节点上+5,他们的LCA(root)-5,父节点也-5,单点query时就查子树和就好了

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005, P = 20;
int in[maxn], f[maxn], head[2 * maxn],to[2 * maxn],last[2 *maxn],co[2 * maxn];
int idx, anc[maxn][P+1], dep[maxn], out[maxn], seq[maxn], idx1;
vector <int> G[maxn];
int n,m;
void dfs(int u,int from){
    in[u] = ++idx;
    
    anc[u][0] = from;
    //fprintf(stderr, "from = %d  u = %d\\n",from, u);
    for(int p = 1; p <= P; p++) {
    //    fprintf(stderr, "p = %d anc[%d][%d] = %d\\n", p, u, p, anc[u][p]);
        anc[u][p] = anc[anc[u][p-1]][p-1];
    }
    for(int i = head[u]; i; i = last[i]){
        int v = to[i];
        if(v != from){
            dep[v] = dep[u] + 1;
            f[v] = u;
            dfs(v,u);
        }
    }    
    out[u] = idx;
}
int lca(int u,int v){//倍增求LCA
    if(dep[u] < dep[v])swap(u, v);
    int t = dep[u] - dep[v];
    for(int p = 0; t; t >>= 1, p++)
        if(t & 1)u = anc[u][p];
    if(u == v)return v;
    
    for(int p = P; p >=0; p--)
        if(anc[u][p] != anc[v][p])
            u = anc[u][p], v = anc[v][p];
    return anc[u][0];
}
int query(int x){
    int ret = 0;
    while(x > 0){
        ret += seq[x];
        x -= (x & -x);
    }
    return ret;
}

void issum(int x,int val){
    while(x <= n){
        seq[x] += val;
        x += (x & -x);
    }
}
void adde(int u,int v){
    idx1++;
    last[idx1] = head[u];
    to[idx1] = v;    
    head[u] = idx1;
}
int main(){
    freopen("redpacket2.in","r",stdin);
    freopen("redpacket2.out","w",stdout);
    //ios::sync_with_stdio(false);
    cin>>n;
    for(int i = 1; i < n; i++){
        int u,v;
        scanf("%d%d",&u,&v);
        adde(u,v);
        adde(v,u);
    }
    f[1] = 0;
    dep[1] = 1;
    dfs(1,1);    
    cin>>m;
    for(int i = 1;i <= m; i++){
        string opt;
        cin>>opt;
        if(opt[0] == \'s\'){
            int u;
            scanf("%d",&u);
            printf("%d\\n",query(out[u])-query(in[u]-1));
        }
        else{
            int u,v,val;
            scanf("%d%d%d",&u,&v,&val);
            issum(in[u],val);
            issum(in[v],val);
            int q = lca(u, v);
            issum(in[q],-val);
            int  p = f[q];
            if(p != 0)
            issum(in[p],-val);
        }
    }
}

 

以上是关于18寒假第三测的主要内容,如果未能解决你的问题,请参考以下文章

ZR十连测第三测

9.11ZR七连测第三测总结

第三次寒假作业

三测单绘制

寒假第三天

寒假每一天