BZOJ 4009 HNOI2015 接水果 树套树

38 篇文章 0 订阅
32 篇文章 0 订阅

题目大意:给定一棵树和 m <script type="math/tex" id="MathJax-Element-32">m</script>条路径,每条路径有一个权值,Q次询问,每次询问某条路经包含的所有路径中权值的第k小
原来精神污染那个题是这么做的啊QwQ
题解网上都有,我就直接贴代码了
没心情写题解了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 40400
using namespace std;
struct Line{
    int type;
    int x,y1,y2,z;
    Line() {}
    Line(int _,int __,int ___,int ____,int _____):
        type(_),x(__),y1(___),y2(____),z(_____) {}
    bool operator < (const Line &l) const
    {
        if(x!=l.x)
            return x < l.x;
        return type > l.type;
    }
}lines[M<<2];
struct Query{
    int x,y,k,id;
    bool operator < (const Query &q) const
    {
        return x < q.x ;
    }
}queries[M];
struct abcd{
    int to,next;
}table[M<<1];
int head[M],_tot;
int n,m,q,tot;
int dpt[M],fa[M][16],st[M],ed[M];
int ans[M];
void Add(int x,int y)
{
    table[++_tot].to=y;
    table[_tot].next=head[x];
    head[x]=_tot;
}
void DFS(int x)
{
    static int T;
    int i;
    dpt[x]=dpt[fa[x][0]]+1;
    st[x]=++T;
    for(i=head[x];i;i=table[i].next)
        if(table[i].to!=fa[x][0])
        {
            fa[table[i].to][0]=x;
            DFS(table[i].to);
        }
    ed[x]=T;
}
int LCA(int x,int y)
{
    int j;
    if(dpt[x]<dpt[y])
        swap(x,y);
    for(j=15;~j;j--)
        if(dpt[fa[x][j]]>=dpt[y])
            x=fa[x][j];
    if(x==y) return x;
    for(j=15;~j;j--)
        if(fa[x][j]!=fa[y][j])
            x=fa[x][j],y=fa[y][j];
    return fa[x][0];
}
int Second_LCA(int x,int y)
{
    int j;
    for(j=15;~j;j--)
        if(dpt[fa[y][j]]>dpt[x])
            y=fa[y][j];
    return y;
}
void Insert_Rectangle(int x1,int x2,int y1,int y2,int z)
{
    lines[++tot]=Line(1,x1,y1,y2,z);
    lines[++tot]=Line(-1,x2+1,y1,y2,z);
}
struct Segtree{
    Segtree *ls,*rs;
    int cnt;
    void* operator new (size_t)
    {
        static Segtree *mempool,*C;
        if(C==mempool)
            mempool=(C=new Segtree[1<<16])+(1<<16);
        C->ls=C->rs=0x0;
        C->cnt=0;
        return C++;
    }
    friend void Modify(Segtree *&p,int x,int y,int pos,int val)
    {
        int mid=x+y>>1;
        if(!p) p=new Segtree;
        p->cnt+=val;
        if(x==y)
            return ;
        if(pos<=mid)
            Modify(p->ls,x,mid,pos,val);
        else
            Modify(p->rs,mid+1,y,pos,val);
    }
    friend int Get_Kth(Segtree *stack[],int top,int x,int y,int k)
    {
        int i,mid=x+y>>1,cnt=0;
        if(x==y) return mid;
        for(i=1;i<=top;i++)
            cnt+=stack[i]&&stack[i]->ls?stack[i]->ls->cnt:0;
        if(k<=cnt)
        {
            for(i=1;i<=top;i++)
                stack[i]=stack[i]?stack[i]->ls:0x0;
            return Get_Kth(stack,top,x,mid,k);
        }
        else
        {
            for(i=1;i<=top;i++)
                stack[i]=stack[i]?stack[i]->rs:0x0;
            return Get_Kth(stack,top,mid+1,y,k-cnt);
        }
    }
};
namespace BIT{
    Segtree *c[M];
    void Update(int x,int pos,int val)
    {
        for(;x;x-=x&-x)
            Modify(c[x],0,1000000000,pos,val);
    }
    int Get_Kth(int x,int k)
    {
        static Segtree *stack[M];int top;
        top=0;
        for(;x<=n;x+=x&-x)
            stack[++top]=c[x];
        return Get_Kth(stack,top,0,1000000000,k);
    }
}
int main()
{
    using namespace BIT;
    int i,j,x,y,z;
    cin>>n>>m>>q;
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        Add(x,y);Add(y,x);
    }
    DFS(1);
    for(j=1;j<=15;j++)
        for(i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1];
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        if(st[x]>st[y])
            swap(x,y);
        int lca=LCA(x,y);
        if(lca!=x)
            Insert_Rectangle(st[x],ed[x],st[y],ed[y],z);
        else
        {
            int temp=Second_LCA(x,y);
            if(st[temp]!=1)
                Insert_Rectangle(1,st[temp]-1,st[y],ed[y],z);
            if(ed[temp]!=n)
                Insert_Rectangle(st[y],ed[y],ed[temp]+1,n,z);
        }
    }
    sort(lines+1,lines+tot+1);
    for(i=1;i<=q;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        if(st[x]>st[y])
            swap(x,y);
        queries[i].x=st[x];
        queries[i].y=st[y];
        queries[i].k=z;
        queries[i].id=i;
    }
    sort(queries+1,queries+q+1);
    for(j=1,i=1;i<=q;i++)
    {

        for(;j<=tot&&lines[j].x<=queries[i].x;j++)
            Update(lines[j].y1-1,lines[j].z,-lines[j].type),
            Update(lines[j].y2,lines[j].z,lines[j].type);

        ans[queries[i].id]=Get_Kth(queries[i].y,queries[i].k);

    }
    for(i=1;i<=q;i++)
        printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 有一个 $n$ 个点的棋盘,每个点上有一个数字 $a_i$,你需要从 $(1,1)$ 走到 $(n,n)$,每次只能往右或往下走,每个格子只能经过一次,路径上的数字和为 $S$。定义一个点 $(x,y)$ 的权值为 $a_x+a_y$,求所有满足条件的路径中,所有点的权值和的最小值。 输入格式 第一行一个整数 $n$。 下来 $n$ 行,每行 $n$ 个整数,表示棋盘上每个点的数字。 输出格式 输出一个整数,表示所有满足条件的路径中,所有点的权值和的最小值。 数据范围 $1\leq n\leq 300$ 输入样例 3 1 2 3 4 5 6 7 8 9 输出样例 25 算法1 (形dp) $O(n^3)$ 我们可以先将所有点的权值求出来,然后将其看作是一个有权值的图,问题就转化为了在这个图中求从 $(1,1)$ 到 $(n,n)$ 的所有路径中,所有点的权值和的最小值。 我们可以使用形dp来解决这个问题,具体来说,我们可以将这个图看作是一棵,每个点的父节点是它的前驱或者后继,然后我们从根节点开始,依次向下遍历,对于每个节点,我们可以考虑它的两个儿子,如果它的两个儿子都被遍历过了,那么我们就可以计算出从它的左儿子到它的右儿子的路径中,所有点的权值和的最小值,然后再将这个值加上当前节点的权值,就可以得到从根节点到当前节点的路径中,所有点的权值和的最小值。 时间复杂度 形dp的时间复杂度是 $O(n^3)$。 C++ 代码 算法2 (动态规划) $O(n^3)$ 我们可以使用动态规划来解决这个问题,具体来说,我们可以定义 $f(i,j,s)$ 表示从 $(1,1)$ 到 $(i,j)$ 的所有路径中,所有点的权值和为 $s$ 的最小值,那么我们就可以得到如下的状态转移方程: $$ f(i,j,s)=\min\{f(i-1,j,s-a_{i,j}),f(i,j-1,s-a_{i,j})\} $$ 其中 $a_{i,j}$ 表示点 $(i,j)$ 的权值。 时间复杂度 动态规划的时间复杂度是 $O(n^3)$。 C++ 代码

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值