【lcyz】noip模拟题

题目来自友好外交的聊城一中~

由于我是自己闲的做的,LOI做的人不多……

战绩:T1:100,T2:20(数组开小+lld),T3:0(输入有问题【据说?】+lld)

后来把T2T3傻X错误改了然后AK了,不得不说眼瞎真是害死人!!

注意!!!这里的代码是我120分的代码!!请注意T3的输入【据说?】!!
还有就是不要像我一样傻X全开longlong,会T!!!
出题人语文我给十分!!


T1:

紫电穿风刺

【问题描述】

“紫电穿风刺” 是棂根据低密度中子纤维束集成剑质量轻、 硬度大、 韧性好的特点结合
自己并不深厚的法力和最新研究的在理论自然学上具有革命意义的光子电效应理论, 创造出
的一种新型剑法。 这一招也是目前棂所有近身招数中的必杀技。 此招发动的最后阶段是把前
期光子电效应产生的电能附着在剑锋上, 随后是量子干扰削弱对手的意志和精神集中程度并
间接降低对手的速度和防御能力, 然后剑体幻化出若干实体, 从不同的角度高伤害地刺击对
手,实现对对手身体和精神两方面的重创。
“紫电穿风刺” 威力的大小与前期光子电效应积累的电能有很大关系。 前期, 出招者发
动符咒, 开辟出 n 条从符咒到对手的量子通道, 同时产生 n 个光子, 然后这 n 个光子随机地
穿过这 n 条通道到达对手附近准备实施量子干扰。如果第 i 个光子恰好穿过了第 i 条通道,
那么由光子电效应理论,这个光子会在符咒的作用下产生
ai 的电能,并消耗出招者一定的
法力, 其中产生的电能正比于消耗的法力, 比值是 k 。 由于这种招式威力具有随机性, 我们
只关心出招者使出此招需要消耗法力的数学期望。
其实积累电能的时候,出招者如果离对手足够近,还能造成电弧伤害。

【输入】

第一行两个整数 n 和 k,代表一共有 n 个光子,产生的电能和消耗的法力的比值为 k 。
第二行有 n 个整数,第 i 个整数
i
a 表示如果第 i 个光子通过第 i 条通道,将产生
i
a 的电
能。

【输出】

只有一行,为一个实数,代表这次攻击消耗法力的数学期望,保留三位小数。

【输入输出样例】

输入:
2 1
1 1

输出:
1.000

【输入输出样例说明】

光子穿过通道的方案只能是(1,2) (表示第一个光子穿过第 1 条通道, 第二个光子穿过
第 2 条通道)和(2,1) (表示第一个光子穿过第 2 条通道,第二个光子穿过第 1 条通道) 。
其中(1,2)产生的电能为[1=1]+[2=2]=1+1=2,消耗法力为 2,发生概率为 0.5; (2,1)产生
的电能为[1=2]+[2=1]=0+0=0,消耗法力为 0,发生概率为 0.5,所以消耗法力的数学期望是
2*0.5+0*0.5=1.000。

【数据范围】

对于 10%的数据, 10 ≤ n ;
对于 50%的数据, 5000 ≤ n ;
对于 100%的数据, 1000 1 , 10000 ] [ 1 , 500000 ≤ ≤ ≤ ≤ ≤ k i a n ;
对于另外 20%的数据, 1 = k 。


我真的没做过数学期望的题,这题挺水的。
对于第i个,有1/n的几率选到,因为k倍,所以要除以k,累加起来即可。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;


int main()
{
    freopen("stab.in","r",stdin);
    freopen("stab.out","w",stdout);
    int n;
    double k;
    scanf("%d%lf",&n,&k);
    double ans=0;
    for(int i=1;i<=n;i++)
    {
        double x;
        scanf("%lf",&x);
        ans+=x/((double)n)/k;
    }
    printf("%.3lf\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}


T2:

血雾绝杀

【问题描述】

棂吐血三尺,正用剑拄着地面,艰难地撑着自己不倒下。
拉尔法狂妄地笑着: “这就是你上次偷袭我的代价! ”
细如雨丝的鲜血悬浮在空中,在我眼前染出一片淡淡的红。
但此时我收到了计算请求。
棂: “你只管算,否则可能真的没有机会了! ”
棂要使用禁术“血雾绝杀” 。战斗中被打吐血几乎可以说是战败了,但自己的血里本身
就蕴含着属于自己的力量。
棂的血雾已扩散到足够远, 但拉尔法不知道自己已身处棂的最后一个陷阱中。 客观上来
讲这确实是一个好机会,不过要抓住它必定要付出惨痛的代价。
棂要给 n 个点分配合适的势能以达到绝杀的目的。
何谓“合适” ?就是势能要同时满足 m 条关系。 若一个关系是 < a,b,c > , 那么 a 点就必须
比 b 点少分配 c 的势能。
每个点的势能当然不能是负的。
分配势能需要消耗法力,显然棂此时要消耗最少的法力完成分配。
棂只关心自己最少需要拿出多少势能,才能使 n 个点分配的势能“合适” 。至于每个点
具体要分配多少的问题,符咒会解决。
你能帮我吗?
要快,我只能等 10s。

【输入】

第一行为两个整数 n 和 m,表示有 n 个点需要分配势能,有 m 条需要满足的关系。
接下来 m 行,每行 3 个整数 a,b,c,代表点 a 要比点 b 少分配至少 c 点势能。

【输出】

只有一行, 为所需要的最小总势能。如果无解, 请输出“-1” (不含引号) ,不过那样的
话棂真是太不幸了。

【输入输出样例】

样例输入1:
5 8
1 2 0
2 1 0
3 2 1
1 4 1
5 4 0
4 5 0
3 5 1
1 5 1

样例输出1:
6

样例输入2:
3 3
1 2 1
2 3 1
3 1 1

样例输出2:
-1

【输入输出样例说明】

样例一,最少时要给这 5 个点分别分配 1、1、0、2、2 的势能。
样例二,显然无解。

【数据范围】

对于 40%的数据,1 <= n,m<=1000 , c <= 10;
对于 100%的数据,1 <= n,m <= 100000 , c<=100 , 1 <= a ,b <= n;

【提示】

这个题还用不着写高精度。
棂通常很幸运,所以不会有多少“-1” 。


一眼题:差分约束裸题。
因为要求最小值,所以跑最长路。
数据有丧病网格图,我加的SPFA+SLF秒过。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const LL size=500010;
const LL INF=23333333333333333;
LL head[size],nxt[size],tot=0;
LL dist[size];

struct edge{
    LL t;
    LL d;
}l[size];

void build(LL f,LL t,LL d)
{
    l[++tot].t=t;
    l[tot].d=d;
    nxt[tot]=head[f];
    head[f]=tot;
}
LL n,m;
deque<LL> q;
bool use[size];
LL t[size];
bool spfa(LL s)
{
    for(register LL i=1;i<=n;i++) dist[i]=-INF;
    dist[s]=0;
    q.push_front(s);
    use[s]=1;
    while(q.size())
    {
        LL f=q.front(); q.pop_front();
        use[f]=0;
        for(register LL i=head[f];i;i=nxt[i])
        {
            LL v=l[i].t;
            if(dist[v]<dist[f]+l[i].d)
            {
                dist[v]=dist[f]+l[i].d;
                if(!use[v])
                {
                    use[v]=1;
                    if(q.empty()) q.push_front(v);
                    else if(dist[q.front()]<dist[v])
                    {
                        q.push_front(v);
                    }
                    else
                    {
                        q.push_back(v);
                    }
                    if(++t[v]>n) return true;
                }
            }
        }
    }
    return false;
}

int main()
{
    freopen("impasse.in","r",stdin); 
    freopen("impasse.out","w",stdout); 
    scanf("%lld%lld",&n,&m);
    for(register LL i=1;i<=m;i++)
    {
        LL a,b;
        LL c;
        scanf("%lld%lld%lld",&a,&b,&c);
        build(a,b,c);
    }
    for(register LL i=n;i>=1;i--)
    {
        build(n+1,i,0);
    }
    if(spfa(n+1)) puts("-1");
    else
    {
        LL ans=0,minn=0;
        for(register LL i=1;i<=n;i++)
        {
            ans+=dist[i];
            minn=min(minn,dist[i]);
        }
        if(minn<0) ans+=-minn*n;
        printf("%lld\n",ans);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}


T3:

闪电风暴

【问题描述】

“闪电风暴” 是棂为了弥补远距离杀伤力不足的缺陷, 利用由光电子效应理论支撑的符
咒电子的空间灵活性, 新创的远距离大面积攻击术。 由于其具有巨大的有效攻击空间和不错
的攻击力,因此可以实现远距离群攻和覆盖打击。 “闪电风暴”由符咒催动,使用者用咒语
和法力交换符咒的威力。
在刚才 Monitor 进攻的过程中, 棂已经发现这 n 个“黑洞” 虽然看似多变, 也即通道很
多, 但拉尔法的四维技术也就是半瓶子醋, 所以棂很轻易地在发动符咒的同时借符咒的威力
钳制住了大部分通道, 同时封锁了大量四维空间, 只剩下 n 个四维空间和 n-1 条能量比较高
的通道还勉强可以传送拉尔法自己。
随后棂在符咒的协同下对 “黑洞术” 发动攻击。 棂、 符咒和拉尔法分别在三个四维空间
上,其中棂和拉尔法的位置不同。符咒和拉尔法之间有一条经过若干条通道的“路” (不能
重复走某条通道,即使是从不同的方向) 。若棂在某一位置对拉尔法展开进攻,他需要向符
咒和拉尔法之间的 “路” 传输攻击能量。 这些攻击能量必须不小于棂到那条 “路” 所经过的
所有通道中传输能量最大的通道的传输能量值。
当这些攻击能量被传输到 “路” 上时, 符咒被激活, 并释放大小为 “路” 上所有通道中
传输能量最大的通道的传输能量值。 棂这次攻击的攻击力, 就是棂的攻击能量和符咒释放的
能量的总和。
拉尔法的活动空间已经很狭小了,要想躲开这样的攻击想必要费很大力气吧。

【输入】

第一行为两个整数 n 和 position,代表初始状态已展开成四维空间的总数和符咒所处的
四维空间的编号。
接下来 n-1 行,每行有三个整数 a,b,c,代表从编号为 a 的四维空间到编号为 b 的四
维空间有一条通路。
接下来一行,有一个整数 q,代表所有事件的总数。
接下来 q 行,每行一开始有一串字符。若字符为 Query,则该行还有两个整数 a、b, 意
为询问当棂在编号为 a 的四维空间、 拉尔法在编号为 b 的四维空间时, 棂传输最小攻击能量
的情况下所能造成的攻击力;若字符为 Add,则该行还有两个整数 a、b,意为拉尔法困兽
犹斗, 销减了大量法力展开了一个新的四维空间, 这个新空间和 a 有一条通道, 传送能量为
b;若字符为 Change,则该行还有一个整数 a,意为棂为了更好地完成攻击,把符咒的位置
转移到编号为 a 的四维空间。

【输出】

对于每一个 Query 操作,输出一行一个整数,表示这个 Query 操作的答案。

【输入输出样例】

样例输入:
4 1
1 2 1
1 3 1
2 4 1
5
Query 3 4
Add 3 5
Query 3 5
Change 5
Query 1 4

样例输出:
2
5
5

【输入输出样例说明】

先运行 mspaint;
Query 3 4:拉尔法在 4 号空间, “路”是 4->2->1, “路”上传送能量最高的通道是(4,2)
或(2,1),其权值为 1;棂在 3 号空间,到“路”所经过的所有通道中传送能量最高的通道是
(4,1),其权值为 1;所以对这一组询问,应该输出 1+1=2;
Add 3 5: 加入一个新的点, 编号是 4+1=5, 与它相连的点为 a=3, 通道(3,5)的权值是 b=5;
Query 3 5: 拉尔法在 5 号空间, “路” 是 5->3->1, “路” 路上传送能量最高的通道是(5,3),
其权值为 1;棂在 3 号空间,到“路”不需经过任何通道,其权值视为 0;所以对这一组询
问,应该输出 5+0=5;
Change 5:把当前符咒所在的位置修改为 5 号结点;
Query 1 4:拉尔法在 4 号空间, “路”是 4->2->1->3->5, “路”上传送能量最高的通道
是(3,5),其权值为 5;棂在 1 号空间,到“路”不需经过任何通道,其权值视为 0;所以对
2015NOIP 模拟题 提高组 Day2
第 10 页 共 10 页
这一组询问,应该输出 5+0=5;

【数据范围】

输入数据保证程序执行过程中总点数不超过 n+tot。

数据点比例Change 操作数量(n+tot)范围Add 操作Query 操作数量
20%0[1,1000][1,1000]
40%0[1,100000][1,100000]
60%0[1,100000][1,100000]
80%[1,50][1,10000][1,10000]
100%[1,50][1,10000][1,100000]
110%[1,100000][1,100000][1,100000]

【提示】

出第十一组数据是为了提高大家踩 std 的难度,也给神犇们一个完虐 std 的机会,不影
响大家 300 分获得 AK 荣誉勋章。


终于到重头戏了。

先简述一下题意:

给你一颗树,规定一个点是特殊点(记为点c)。现给你三个操作:
1,查询操作。给定a和b,求a到路径 < b,c > 的路径上,权值最大的边的权值ans1,和路径 < b,c > 上权值最大边ans2的和,即ans1+ans2。
2,加点操作。新加一个点,编号为++n,父亲是a,与a的连边权值为b。
3,修改操作。修改特殊点的位置。

查询的具体意义,如图所示:
要求路径ad和路径bc上权值最大的边的权值之和,路径上的点省略了
要求路径ad和路径bc上权值最大的边的权值之和,路径上的点省略了


如何查询?

这个问题纠结我好久。对于已经确定起始点的bc路径上的答案,可以直接求解。问题是如何求解ad路径上的答案。

总结了一下,一共有如下三种情况:

为了方便,以下用xy代表LCA(x,y)。例如ab=LCA(a,b)。
以下用dist(x,y)表示ab路径上的答案(也就是权值最大的边)。

第一种情况:

可以简述为ac=bc

可以简述为ac=bc。答案就是dist(a,ab)。

第二种情况:

可以简述为ab=bc

可以简述为ab=bc。答案就是dist(a,ac)。

第三种情况:

可以简述为ab=ac

可以简述为ab=ac。答案就是dist(a,bc)。

一共就这三种情况,其他特殊情况(如链等等)都可以归为这三种情况之内。
不可能出现三个点两两LCA互不相同的情况,可以证明。


利用倍增LCA,对于每次查询,查询三个LCA,查询两点距离,每种操作都是O(logn)的。

这样操作其实对于c点具体位置无关,修改可以做到O(1)。

由于添加仅仅加了一个点,所以只需要对这一个点进行倍增就可以了,复杂度O(logn)

这样算法复杂度nlogn,可以完爆std了。

/*
这里插一句,据说std做的110分是LCT,据说100分的std的做法对于单个change的复杂度是nlogn的,不过查询很简单。虽然我并不知道怎么做的……
*/


代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL size=250010;
const LL INF=233333333;
LL head[size],nxt[size],tot=0;

struct edge{
    LL t,d;
}l[size];

void build(LL f,LL t,LL d)
{
    l[++tot].t=t;
    l[tot].d=d;
    nxt[tot]=head[f];
    head[f]=tot;
}


LL deep[size],anc[size][30],maxx[size][30];

void dfs(LL u,LL fa)
{
    if(deep[u]) return ;
    deep[u]=deep[fa]+1;
    anc[u][0]=fa;
    for(LL i=1;anc[u][i-1];i++)
    {
        anc[u][i]=anc[anc[u][i-1]][i-1];
        maxx[u][i]=max(maxx[u][i-1],maxx[anc[u][i-1]][i-1]);
    }
    for(LL i=head[u];i;i=nxt[i])
    {
        LL v=l[i].t;
        if(!deep[v]) 
        {
            maxx[v][0]=l[i].d;
            dfs(v,u);
        }
    }
}

LL asklca(LL x,LL y)
{
    if(deep[x]<deep[y]) swap(x,y);
    if(deep[x]>deep[y]) 
    {
        LL dd=deep[x]-deep[y];
        for(LL i=0;i<=24;i++)
        {
            if(dd&(1<<i))
            {
                x=anc[x][i];
            }
        }
    }
    if(x!=y)
    {
        for(LL i=24;i>=0;i--)
        {
            if(anc[x][i]!=anc[y][i])
            {
                x=anc[x][i];
                y=anc[y][i];
            }
        }       
    }
    if(x==y) return x;
    else return anc[x][0];
}

LL askdist(LL x,LL y)
{
    LL ans=0;
    if(deep[x]<deep[y]) swap(x,y);
    if(deep[x]>deep[y]) 
    {
        LL dd=deep[x]-deep[y];
        for(LL i=0;i<=24;i++)
        {
            if(dd&(1<<i))
            {
                ans=max(ans,maxx[x][i]);
                x=anc[x][i];
//              cout<<ans<<endl;
            }
        }
    }
    if(x!=y)
    {
        for(LL i=24;i>=0;i--)
        {
            if(anc[x][i]!=anc[y][i])
            {
                ans=max(ans,max( maxx[x][i],maxx[y][i] ));
                x=anc[x][i];
                y=anc[y][i];
            }
        }       
    }
    if(x==y) return ans;
    else return max(ans,max(maxx[x][0],maxx[y][0]));
}

int main()
{
    freopen("lightningstorm.in","r",stdin);
    freopen("lightningstorm.out","w",stdout);
    LL n,c;
    scanf("%lld%lld",&n,&c);
    for(LL i=1;i<=n-1;i++)
    {
        LL a,b,c;
        scanf("%lld%lld%lld",&a,&b,&c);
        build(a,b,c);
        build(b,a,c);
    }
    dfs(1,0);


    LL q;
    scanf("%lld",&q);
    while(q--)
    {
        char s[10];
        LL a,b;
        scanf("%s",s);
        if(s[0]=='Q')
        {
            LL a,b;
            scanf("%lld%lld",&a,&b);
            LL ab=asklca(a,b);
            LL bc=asklca(b,c);
            LL ac=asklca(a,c);
            LL ans=askdist(c,b);
    //      cout<<a<<" "<<b<<" "<<c<<" "<<ab<<" "<<bc<<" "<<ac<<endl;
            if(ab==ac)
            {
                printf("%lld\n",askdist(bc,a)+ans);
            }
            else if(ab==bc)
            {
                printf("%lld\n",askdist(ac,a)+ans);
            }
            else if(ac==bc)
            {
                printf("%lld\n",askdist(ab,a)+ans);
        //      puts("fuck");
            }
        }
        else if(s[0]=='A')
        {
            LL a,b;
            scanf("%lld%lld",&a,&b);
            LL u=++n;
            anc[u][0]=a;
            maxx[u][0]=b;
            deep[u]=deep[a]+1;
            for(LL i=1;anc[u][i-1];i++)
            {
                anc[u][i]=anc[anc[u][i-1]][i-1];
                maxx[u][i]=max(maxx[u][i-1],maxx[anc[u][i-1]][i-1]);
            }
            /*      for(LL i=1;i<=n;i++)
                    {
                        for(LL j=0;j<=5;j++)
                        {
                            printf("%d ",anc[i][j]);
                        }
                        puts("");
                    }*/
        }
        else
        {
            LL a;
            scanf("%lld",&a);
            c=a;
        }
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
/*
4 1
1 2 1
1 3 1
2 4 1
5
Query 3 4
Add 3 5
Query 3 5
Change 5
Query 1 4


7 3
1 2 1
1 3 3
1 7 5
3 6 13
3 5 10
3 4 9
10
Query 5 7
Query 4 6
Change 2
Add 2 6
Query 8 3
Query 1 5
Change 6
Query 4 5
Add 5 10
Query 8 9

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值