BZOJ 1224 HNOI2002 彩票 DFS

题目大意:在1~m中选n个不同的数 要求和为X/Y 求方案数

爆搜的话应该是100E左右 所以考虑加剪枝

上下界剪枝 如果当前的情况下剩余的数最大都无法到达目标或最小都无法小于目标 则剪枝

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
struct Segtree{
    Segtree *ls,*rs;
    int num;
    void* operator new (size_t size,Segtree *_,Segtree *__,int ___);
}*tree[M],*mempool,*C;
struct edge{
    int x,y,f;
    bool operator < (const edge &Y) const
    {
        return f < Y.f ;
    }
}edges[500500];
struct abcd{
    int to,next;
}table[M];
int head[M],tot;
int n,m,q,ans;
int a[M],fa[M][20],dis[M][20],belong[M];
int seq[M],l[M],r[M],cnt;
void* Segtree :: operator new (size_t size,Segtree *_,Segtree *__,int ___)
{
    if(C==mempool)
    {
        C=new Segtree[1<<15];
        mempool=C+(1<<15);
    }
    C->ls=_;
    C->rs=__;
    C->num=___;
    return C++;
}
void Add(int x,int y)
{
    table[++tot].to=y;
    table[tot].next=head[x];
    head[x]=tot;
}
int Find(int x)
{
    if(!belong[x]||belong[x]==x)
        return belong[x]=x;
    return belong[x]=Find(belong[x]);
}
void Kruskal()
{
    int i;
    sort(edges+1,edges+m+1);
    for(i=1;i<=m;i++)
    {
        int x=Find(edges[i].x);
        int y=Find(edges[i].y);
        if(x==y) continue;
        belong[x]=belong[y]=++n;
        fa[x][0]=fa[y][0]=n;
        dis[x][0]=dis[y][0]=edges[i].f;
        Add(n,x);Add(n,y);
        printf("%d %d\n",n,x);
        printf("%d %d\n",n,y);
        printf("%d[label=\"%d\",fontcolor=red]\n",n,edges[i].f);
    }
}
void DFS(int x)
{
    int i;
    seq[l[x]=++cnt]=a[x];
    for(i=head[x];i;i=table[i].next)
        DFS(table[i].to);
    r[x]=cnt;
}
Segtree* Build_Tree(Segtree *p,int x,int y,int val)
{
    int mid=x+y>>1;
    if(x==y) return new (0x0,0x0,p->num+1) Segtree;
    if(val<=mid) return new (Build_Tree(p->ls,x,mid,val),p->rs,p->num+1) Segtree;
    else return new (p->ls,Build_Tree(p->rs,mid+1,y,val),p->num+1) Segtree;
}
int Get_Kth(Segtree *p1,Segtree *p2,int x,int y,int k)
{
    int mid=x+y>>1;
    if(x==y) return mid;
    int temp=p2->rs->num-p1->rs->num;
    if(k<=temp) return Get_Kth(p1->rs,p2->rs,mid+1,y,k);
    else return Get_Kth(p1->ls,p2->ls,x,mid,k-temp);
}
int Get_Root(int x,int y)
{
    int j;
    for(j=19;~j;j--)
        if( fa[x][j] && dis[x][j]<=y )
            x=fa[x][j];
    return x;
}
int main()
{
    int i,j,v,x,k;
    cin>>n>>m>>q;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(i=1;i<=m;i++)
        scanf("%d%d%d",&edges[i].x,&edges[i].y,&edges[i].f);
    Kruskal();
    for(j=1;j<=19;j++)
        for(i=1;i<=n;i++)
            fa[i][j]=fa[fa[i][j-1]][j-1],
            dis[i][j]=max(dis[i][j-1],dis[fa[i][j-1]][j-1]);
    DFS(n);
    tree[0]=new (0x0,0x0,0) Segtree;
    tree[0]->ls=tree[0]->rs=tree[0];
    for(i=1;i<=n;i++)
        tree[i]=Build_Tree(tree[i-1],0,1000000000,seq[i]);
    for(i=1;i<=q;i++)
    {
        scanf("%d%d%d",&v,&x,&k);
        //x^=ans;v^=ans;k^=ans;
        int root=Get_Root(v,x);
        if(r[root]-l[root]+1<k)
        {
            puts("-1");
            ans=0;
            continue;
        }
        ans=Get_Kth(tree[l[root]-1],tree[r[root]],0,1000000000,k);
        if(!ans)
        {
            puts("-1");
            continue;
        }
        printf("%d\n",ans);
    }
}
时间: 2024-10-12 10:41:51

BZOJ 1224 HNOI2002 彩票 DFS的相关文章

BZOJ 1588: [HNOI2002]营业额统计 双向链表

BZOJ 1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 9619  Solved: 3287 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1588 Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来

BZOJ1224 [HNOI2002]彩票

首先发现暴搜是2^50级别,明显T了 我们搜索的时候,剪枝一下. 如果当前最大最小值都不满足满足题意的话就不搜了,我们可以用前缀和维护这个东西 于是就6s卡过 1 /************************************************************** 2     Problem: 1224 3     User: rausen 4     Language: C++ 5     Result: Accepted 6     Time:6800 ms 7  

BZOJ 1588: [HNOI2002]营业额统计

1588: [HNOI2002]营业额统计 Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 14396  Solved: 5521[Submit][Status][Discuss] Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其

BZOJ 1024: [SCOI2009]生日快乐 dfs

1024: [SCOI2009]生日快乐 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1024 Description windy的生日到了,为了庆祝生日,他的朋友们帮他买了一个边长分别为 X 和 Y 的矩形蛋糕.现在包括windy,一共有 N 个人来分这块大蛋糕,要求每个人必须获得相同面积的蛋糕. windy主刀,每一切只能平行于一块蛋糕的一边(任意一边

bzoj 1588 [HNOI2002] 营业额统计 链表和Splay

来自HNOI 2002营业额的统计一题,这题以前是用链表水过的,最近看见许多splay的题,赶紧张一下知识. 题目大意就是对于一个序列,输出每个元素与它之前元素的差的最小值的和.先说链表的方法吧. 大概就是sort一下,记录每个点的rank.然后链表一下,很好理解,复杂度nlogn,瓶颈在于排序. #include<cstdio> #include<algorithm> #include<iostream> using namespace std; struct nod

[BZOJ 3306]树(dfs序+线段树+倍增)

Description 给定一棵大小为 n 的有根点权树,支持以下操作: • 换根 • 修改点权 • 查询子树最小值 Solution 单点修改子树查询的话可以想到用dfs序+线段树来处理,换根的处理画一画图应该可以明白: 如果查询的x是当前的根rt,直接返回整棵树的min 如果rt在x的子树中,用倍增的方法找到离x最近的rt的祖先t,整棵树除t的子树以外的部分就是x当前根下的子树 如果rt不在x的子树中,查询x原来的子树的min值 #include<iostream> #include<

BZOJ 1588: [HNOI2002]营业额统计 双向链表 / splay / treap

1588: [HNOI2002]营业额统计 Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题.经济管理学上定义了一种最小波动值来衡量这

BZOJ 2115 Wc2011 Xor DFS+高斯消元

题目大意:给定一个无向图,每条边上有边权,求一条1到n的路径,使路径上权值异或和最大 首先一条路径的异或和可以化为一条1到n的简单路径和一些简单环的异或和 我们首先DFS求出任意一条1到n的简单路径以及图中所有最简单的简单环(环上不存在两个点可以通过环外边直连) 然后在一些数中选出一个子集,使它们与一个给定的数的异或和最大,这就是高斯消元的问题了 利用高斯消元使每一位只存在于最多一个数上 然后贪心求解即可 #include<cstdio> #include<cstring> #in

BZOJ 2208: [Jsoi2010]连通数( DFS )

n只有2000,直接DFS就可以过了... -------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cctype> #define rep( i, n ) for( int i = 0; i