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

原文地址:https://www.cnblogs.com/EdSheeran/p/8428184.html

时间: 2024-08-30 18:13:38

18寒假第三测的相关文章

18寒假第六测

第一题:乘法修改的线段树 一定不能将change,modify分类讨论定两个标记,会有顺序影响 lazy标记一定要long long,又忘了... 代码和上一次差不多 第二题:离散暴力,也可以扫描线 离散时要将格子映射成点,不然会出现以下情况: 算横着的小矩形宽就是2,算黄色面积宽还是2,因为没有2让3去减 如果映射成点,就像这样,,放图比较好理解,就像扫描线,一个叶子节点存的是一个左闭右开的区间 也可以离散+扫描线,但还没写出来 #include <bits/stdc++.h> using

18寒假第五测

第一题 线段树 树状数组存差b[i] = a[i]-a[i-1],反正是单点查询,我为什么没想到...很傻的用线段树 #include<bits/stdc++.h> using namespace std; #define maxn 100005 #define ll long long int n, m, a[maxn]; struct SegmentTree{ struct node{ ll sum; int lazy; }; node Tree[maxn << 2]; #de

医疗系统--体温单(三测单)系统

不同区域的体温单格式不尽相同,本文以江苏某地体温单为范例,介绍完整的体温单系统开发. 1.名词解释 体温单:又叫三测单,是护理病历的一部分.体温单主要用于记录患者的生命体征及有关情况,内容包括患者姓名.年龄.性别.科别.床号.入院日期.住院号(或病案号).日期.住院天数.手术后天数.脉搏.呼吸.体温.血压.出入量.大便次数.体重.身高.页码等. 2.体温单功能点 结合病历书写规范以及医生在临床中的习惯,电子体温单的功能点主要包括以下部分: 分类 序号 功能说明   1 表头(XXX医院,体温单)

三测单绘制

三测单绘制目的1. 体温.脉搏和呼吸曲线的绘制和血压等的 记录,可反映出某种疾病的某一阶段,甚 至反映出病情的好转及恶化. 2. 它们能够协助医生作出正确诊断并为预防. 治疗和护理工作提供依据. 三测单绘制教学要求1. 掌握生命体征的绘制方法. 2. 熟悉三测单眉栏等的填写. 三测单绘制操作流程眉 栏 底栏 脉搏 曲线 绘制 40℃ 线以 上体温曲 线绘制 三测单绘制眉栏1. 用蓝钢笔填写. 2. 姓名.年龄.性别.科别.科室.床号. 住院号.住院日期. 3. 每页第一日填写月日不能用分数表示,

18寒假第一测

猪猪的想法输入文件:thought.in输出文件:thought.out时间限制:1 second空间限制:128 MB题目描述狗蛋养了许多只可爱的猪猪,这些猪猪她萌都有一些奇怪的想法:比如说猪猪喜欢猪猪,猪猪之间的喜欢是一个很有趣的事情--喜欢是可以传递的,例如猪猪喜欢猪猪,猪猪喜欢猪猪,那么可以说猪猪喜欢猪猪.有意思的一点是,她萌不喜欢自恋的猪猪,一旦出现了自恋的猪猪,那么极有可能的是这个团体出现危险.现在给你只猪猪对单方面的关系,请问这个只猪猪组成的团体是否危险呢?是输出Yes ,否输出N

18寒假第二测

第一题:二维树状数组,bit[x][y]表示从(1,1)到(x,y)的和,二维的坐标从一维的推过来,正确性可以用一个递增和一个递减的序列单调性证明,至于构图就当黑箱吧 #include <cstdio> int n, m, q; struct Case1 { int bit[100010]; void modify( int p, int d ) { for( int i = p; i <= m; i += i & -i ) bit[i] += d; } int query( i

18寒假13测

题目名称 buy slide divide 输入 buy.in slide.in divide.in 输出 buy.out slide.out divide.out 每个测试点时限 1秒 1秒 1秒 内存限制 256MB 256MB 256MB 测试点数目 10 10 10 每个测试点分值 10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统 buy description: 地主zxr想买一些长方形的土地,所有的土地可以分为若干组,每一组的土地的价格为这一组里的最长的长乘上最

18寒假12测

Day1 题目名称 party array treasure 输入 party.in array.in treasure.in 输出 party.out array.out treasure.out 每个测试点时限 1秒 1秒 1秒 内存限制 64MB 64MB 64MB 测试点数目 10 10 10 每个测试点分值 10 10 10 是否有部分分 无 无 无 题目类型 传统 传统 传统 party 题目描述: 在M公司里,每个人只有一个直属上司(除了boss).这个公司举办派对,每个人可以给派

寒假第三周反思

寒假已经结束,而我也已经开始了新的学习,希望2019年的自己会更加优秀吧 一.学习 本周的计划是学习js,到目前算是对js理解的差不多了,进度还是可以,先去看菜鸟教程上的,如果又不懂的在结合视频,效率还是比较高的. 二.生活 1.很不幸的事情便是我的电脑又出现了问题,从昨天下午开始,就开始蓝屏,说采集错误信息.我便让大三的学长帮忙修理一下,结果很麻烦.而且上网百度也不是很详细,学长说如果再次蓝屏就给我重装系统.诶,真是麻烦!电脑还是没有手机轻松 2.我从五楼调到了六楼,选择了一个面朝太阳的地方,