一次毒瘤的NOIP模拟赛

2 篇文章 0 订阅
2 篇文章 0 订阅

写在前面

我真的真的好久没有这么sb过了

题目描述

由于fzoj有点狗 所以我把题目附上来
A题
这里写图片描述
B题
这里写图片描述
C题
这里写图片描述

想说的话

刚看到的时候 这题真是太虎了
随便写写就A了
然后我就要自黑一波了 只得了十分也没什么可辩解的
这里写图片描述
但是全都是RE也是很闹挺

A题思路全过程以及题解

刚看到的时候我就在想 最短路果断Dijkstra+Heap
但是这个复杂度有点鬼 果断卡死
然后发现这是一棵树(汗
接着就跑lca(我是倍增选手
跑着跑着发现深度不是距离
就想着把深度赋成距离吧
然后我用距离倍增 真是傻

题解大概都懂
就是找到LCA然后用这两个点到根的距离减去两倍的LCA到根的距离

A题代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define N 200001
#define lowbit(x) x&-x
int head[N],cnt,n,m,dis[N],fa[N][21],k,vs[N];
int deep[N];
struct edge
{
  int to,nxxt,len;
}e[N];
inline void addedge(int u,int v,int len)
{
  cnt++;
  e[cnt].len=len;
  e[cnt].to=v;
  e[cnt].nxxt=head[u];
  head[u]=cnt;
}
inline void superadd(int u,int v,int w)
{
  addedge(u,v,w);
  addedge(v,u,w);
}
void dfs(int now,int f)
{
  for(int i=head[now];i;i=e[i].nxxt)
  {
    int to=e[i].to;
    if(to==f) continue;
    dis[to]=dis[now]+e[i].len;
    deep[to]=deep[now]+1;
    fa[to][0]=now;
    dfs(to,now);
  }
}
inline int getLCA(int u,int v)
{
  if(deep[u]<deep[v]) swap(u,v);
  for(int i=20;i>=0;i--)
  {
    if(deep[ fa[u][i] ]>=deep[v])
    u=fa[u][i];
    if(deep[u]==deep[v]) break;
  }
  if(u==v) return u;
  for(int i=20;i>=0;i--)
  {
    if(fa[u][i]!=fa[v][i])
    {
      u=fa[u][i],v=fa[v][i];
    }
  }
  return fa[u][0];
}
int main()
{
  scanf("%d",&n);
  for(int i=1;i<n;i++)
  {
    int begi,endd,val;
    scanf("%d%d%d",&begi,&endd,&val);
    superadd(begi,endd,val);
  }
  deep[1]=0;
  dfs(1,0);
  for(int i=1;i<=20;i++)
  {
    for(int j=1;j<=n;j++)
    {
      fa[j][i]=fa[fa[j][i-1]][i-1];
    }
  }
  scanf("%d",&m);
  for(int i=1;i<=m;i++)
  {
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%d\n",dis[a]+dis[b]-2*dis[ getLCA(a,b) ]);
  }
}

B题思路全过程以及题解

这题其实我在之前做过类似的
然后写了一个Segtree
打lz标记的时候区间加打成区间修改直接gg
其他的神犇们栽在了long long 上面
真是虎

题解
对于树跑一遍dfs序
之后线段树 区间修改 单点查询 区间查询
超休闲的

B题代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define N 200005
#define M 400005
#define ls q<<1
#define rs q<<1|1
long long head[N],dfn[N],id[N],n,m,cnt,size[N],val[N],tot;
struct edge
{
  long long to,nxxt;
}e[M];
struct treenode
{
  long long begi,endd,sum,lz;
}tree[N<<2];
inline void addedge(long long u,long long v)
{
  cnt++;
  e[cnt].to=v;
  e[cnt].nxxt=head[u];
  head[u]=cnt;
}
inline void superadd(long long u,long long v)
{
  addedge(u,v);
  addedge(v,u);
}
void dfs(long long u,long long fa)
{
  tot++;
  dfn[cnt]=u;
  id[u]=tot;
  size[u]=1;
  for(long long i=head[u];i;i=e[i].nxxt)
  {
    long long to=e[i].to;
    if(to==fa) continue;
    dfs(to,u);
    size[u]+=size[to];
  }
}
inline void buildtree(long long q,long long l,long long r)
{
  tree[q].begi=l,tree[q].endd=r;
  if(l==r)
  {
    tree[q].sum=0;
    return;
  }
  long long mid=(l+r)>>1;
  buildtree(ls,l,mid);
  buildtree(rs,mid+1,r);
  tree[q].sum=tree[ls].sum+tree[rs].sum;
}
inline void pushdown(long long q)
{
  if(tree[q].lz==0) return;
  tree[ls].lz+=tree[q].lz;
  tree[rs].lz+=tree[q].lz;
  tree[ls].sum+=(tree[ls].endd-tree[ls].begi+1)*tree[q].lz;
  tree[rs].sum+=(tree[rs].endd-tree[rs].begi+1)*tree[q].lz;
  tree[q].lz=0;
}
inline void modify(long long q,long long l,long long r,long long x)
{
  if(tree[q].begi>=l&&tree[q].endd<=r)
  {
    tree[q].sum+=(tree[q].endd-tree[q].begi+1)*x;
    tree[q].lz+=x;
    return;
  }
  pushdown(q);
  long long mid=(tree[q].begi+tree[q].endd)>>1;
  if(mid>=r) modify(ls,l,r,x);
  else if(mid<l) modify(rs,l,r,x);
  else
  {
    modify(ls,l,mid,x);
    modify(rs,mid+1,r,x);
  }
  tree[q].sum=tree[ls].sum+tree[rs].sum;
}
inline long long query(long long q,long long l,long long r)
{
  if(tree[q].begi==l&&tree[q].endd==r) return tree[q].sum;
  long long mid=(tree[q].begi+tree[q].endd)>>1;
  pushdown(q);
  if(mid>=r) return query(ls,l,r);
  else if(mid<l) return query(rs,l,r);
  else return query(ls,l,mid)+query(rs,mid+1,r);
}
int main()
{
  char opt[10];
  scanf("%lld",&n);
  for(long long i=1;i<n;i++)
  {
    long long begi,endd;
    scanf("%lld%lld",&begi,&endd);
    superadd(begi,endd);
  }
  dfs(1,0);
  buildtree(1,1,n);
  scanf("%lld",&m);
  for(long long i=1;i<=m;i++)
  {
    scanf("%s",opt);
    if(opt[0]=='g')
    {
      long long x,y;
      scanf("%lld%lld",&x,&y);
      modify(1,id[x],id[x]+size[x]-1,y);
    }
    else if(opt[0]=='s')
    {
      long long x;
      scanf("%lld",&x);
      printf("%lld\n",query(1,id[x],id[x]));
    }
    else
    {
      long long x;
      scanf("%lld",&x);
      printf("%lld\n",query(1,id[x],id[x]+size[x]-1));
    }
  }
}

C题思路全过程以及题解

这题是平衡树裸题
就是插入的时候每个数都有自己的个数
就是需要在插入的时候加上一个权值
最sb的地方就是删除操作可能删除没有的数?!
你tm逗我呢!?
于是乎我们只能用一个hash数组存储一下当前有没有这个数
有几个
然后平衡树就好
我想着splay慢 就第一次尝试了treap
效果还是不错的
就是手贱把fread和scanf一起用了
导致直接RE一分没有

题解
平衡树维护插入 删除 查询第k小
注意判断删除的时候数列里面有没有

C题代码

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
inline int read(){
    char ch=getchar();int sum=0,w=1;
    while(!(ch>='0'&&ch<='9')) {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=getchar();
    return sum*w;
}
struct data
{
    int l,r,v,w,sz,rnd;
}tr[500010];
int n,rt,sze,m;
char opt[10];
inline void update(int k)
{
    tr[k].sz=tr[tr[k].l].sz+tr[tr[k].r].sz+tr[k].w;
}
inline void lturn(int &k)
{
    int t=tr[k].r;
    tr[k].r=tr[t].l;
    tr[t].l=k;
    tr[t].sz=tr[k].sz;
    update(k);
    k=t;
}
inline void rturn(int &k)
{
    int t=tr[k].l;
    tr[k].l=tr[t].r;
    tr[t].r=k;
    tr[t].sz=tr[k].sz;
    update(k);
    k=t;
}
inline void insert(int &k,int x,int y)
{
    if(k==0)
    {
        sze++;
        k=sze;
        tr[k].sz=tr[k].w=y;
        tr[k].v=x;
        tr[k].rnd=rand();
        return;
    }
    tr[k].sz+=y;
    if(tr[k].v==x)tr[k].w+=y;
    else if(x<=tr[k].v)
    {
        insert(tr[k].l,x,y);
        if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);
    }
    else
    {
        insert(tr[k].r,x,y);
        if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k);
    }
}
inline void del(int &k,int x)
{
    if(k==0)return;
    if(tr[k].v==x)
    {
        if(tr[k].w>1)
        {
            tr[k].w--;
            tr[k].sz--;
            return;
        }
        if(tr[k].l*tr[k].r==0)k=tr[k].l+tr[k].r;
        else if(tr[tr[k].l].rnd<tr[tr[k].r].rnd)
        {
            rturn(k);
            del(k,x);
        }
        else
        {
            lturn(k);
            del(k,x);
        }
    }
    else if(tr[k].v>x)
    {
        tr[k].sz--;
        del(tr[k].l,x);
    }
    else
    {
        tr[k].sz--;
        del(tr[k].r,x);
    }
}
inline int que_num(int k,int x)
{
    if(k==0)return 0;
    if(x<=tr[tr[k].l].sz)
    {
        return que_num(tr[k].l,x);
    }
    else if(x>tr[tr[k].l].sz+tr[k].w)
    {
        return que_num(tr[k].r,x-tr[tr[k].l].sz-tr[k].w);
    }
    else return tr[k].v;
}
int fff=100000,haxx[500010];
int main()
{
  int rbound,lbound;
  lbound=read(),rbound=read();
  for(int i=lbound;i<=rbound;i++)
  {
    int num;
    num=read();
    insert(rt,i,num);
    haxx[i+fff]=num;
  }
    n=read();
    for(int i=1;i<=n;i++)
    {
        scanf("%s",opt);
        if(opt[0]=='q')
        {
            m=read();
            update(rt);
            printf("%d",que_num(rt,m));
            putchar(10);
        }
        else if(opt[0]=='a')
        {
            m=read();
            insert(rt,m,1);
            haxx[fff+m]++;
        }
        else {m=read();if(haxx[fff+m]) {del(rt,m);haxx[fff+m]--;}}
    }
}

写在最后

今天真是太sb了
好久没有这么低的分数了
洛谷打卡真是有毒
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值