Ch’s gift

Ch’s gift

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Problem Description

Mr. Cui is working off-campus and he misses his girl
friend very much. After a whole night tossing and turning, he decides to get to
his girl friend‘s city and of course, with well-chosen gifts. He knows neither
too low the price could a gift be since his girl friend won‘t like it, nor too
high of it since he might consider not worth to do. So he will only buy gifts
whose price is between [a,b].
There are n cities in the country and (n-1)
bi-directional roads. Each city can be reached from any other city. In the ith
city, there is a specialty of price ci Cui could buy as a gift. Cui buy at most
1 gift in a city. Cui starts his trip from city s and his girl friend is in city
t. As mentioned above, Cui is so hurry that he will choose the quickest way to
his girl friend(in other words, he won‘t pass a city twice) and of course, buy
as many as gifts as possible. Now he wants to know, how much money does he need
to prepare for all the gifts?

Input

There are multiple cases.

For each case:
The
first line contains tow integers n,m(1≤n,m≤10^5), representing the number of
cities and the number of situations.
The second line contains n integers
c1,c2,...,cn(1≤ci≤10^9), indicating the price of city i‘s specialty.
Then n-1
lines follows. Each line has two integers x,y(1≤x,y≤n), meaning there is road
between city x and city y.
Next m line follows. In each line there are four
integers s,t,a,b(1≤s,t≤n;1≤a≤b≤10^9), which indicates start city, end city,
lower bound of the price, upper bound of the price, respectively, as the exact
meaning mentioned in the description above

Output

Output m space-separated integers in one line, and the
ith number should be the answer to the ith situation.

Sample Input

5 3
1 2 1 3 2
1 2
2 4
3 1
2 5
4 5 1 3
1 1 1 1
3 5 2 3

Sample Output

7 1 4

分析:离线按点权排序,然后树剖;

   或者离散化点权主席树维护有序区间;

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <bitset>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cassert>
#include <ctime>
#define rep(i,m,n) for(i=m;i<=(int)n;i++)
#define mod 1000000007
#define inf 0x3f3f3f3f
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define pi acos(-1.0)
#define pii pair<int,int>
#define sys system("pause")
#define ls rt<<1
#define rs rt<<1|1
#define all(x) x.begin(),x.end()
const int maxn=1e5+10;
const int N=5e5+10;
using namespace std;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qmul(ll p,ll q,ll mo){ll f=0;while(q){if(q&1)f=(f+p)%mo;p=(p+p)%mo;q>>=1;}return f;}
ll qpow(ll p,ll q,ll mo){ll f=1;while(q){if(q&1)f=f*p%mo;p=p*p%mo;q>>=1;}return f;}
int n,m,k,t,a[maxn],fa[maxn],dep[maxn],son[maxn],pos[maxn],bl[maxn],id[maxn],dfs_cl,tot,head[maxn],cnt;
ll ret[maxn],sum[maxn<<2];
struct node
{
    int l,r,id,x;
    bool operator<(const node&p)const
    {
        return x<p.x;
    }
}qu[maxn<<1];
struct node1
{
    int to,nxt;
}e[maxn<<1];
void add(int x,int y)
{
    e[cnt].to=y;
    e[cnt].nxt=head[x];
    head[x]=cnt++;
}
bool cmp(int x,int y)
{
    return a[x]<a[y];
}
void dfs1(int x,int y)
{
    dep[x]=dep[y]+1;
    fa[x]=y;
    son[x]=1;
    for(int i=head[x];i!=-1;i=e[i].nxt)
    {
        int z=e[i].to;
        if(z==y)continue;
        dfs1(z,x);
        son[x]+=son[z];
    }
}
void dfs2(int x,int y,int ch)
{
    int ma=0;
    pos[x]=++dfs_cl;
    bl[x]=ch;
    for(int i=head[x];i!=-1;i=e[i].nxt)
    {
        int z=e[i].to;
        if(z==y)continue;
        if(son[z]>son[ma])ma=z;
    }
    if(ma!=0)dfs2(ma,x,ch);
    for(int i=head[x];i!=-1;i=e[i].nxt)
    {
        int z=e[i].to;
        if(z==y||z==ma)continue;
        dfs2(z,x,z);
    }
}
void build(int l,int r,int rt)
{
    sum[rt]=0;
    if(l==r)return;
    int mid=l+r>>1;
    build(l,mid,ls);
    build(mid+1,r,rs);
}
void pup(int rt)
{
    sum[rt]=sum[ls]+sum[rs];
}
void upd(int x,int y,int l,int r,int rt)
{
    if(x==l&&x==r)
    {
        sum[rt]+=y;
        return;
    }
    int mid=l+r>>1;
    if(x<=mid)upd(x,y,l,mid,ls);
    else upd(x,y,mid+1,r,rs);
    pup(rt);
}
ll Query(int L,int R,int l,int r,int rt)
{
    if(L==l&&R==r)return sum[rt];
    int mid=l+r>>1;
    if(R<=mid)return Query(L,R,l,mid,ls);
    else if(L>mid)return Query(L,R,mid+1,r,rs);
    else return Query(L,mid,l,mid,ls)+Query(mid+1,R,mid+1,r,rs);
}
ll gao(int x,int y)
{
    ll ret=0;
    while(bl[x]!=bl[y])
    {
        if(dep[bl[x]]<dep[bl[y]])swap(x,y);
        ret+=Query(pos[bl[x]],pos[x],1,n,1);
        x=fa[bl[x]];
    }
    if(pos[x]>pos[y])swap(x,y);
    ret+=Query(pos[x],pos[y],1,n,1);
    return ret;
}
int main()
{
    int i,j;
    while(~scanf("%d%d",&n,&m))
    {
        rep(i,1,n)scanf("%d",&a[i]),id[i]=i,head[i]=-1;
        cnt=0;
        rep(i,1,n-1)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        tot=0;
        rep(i,1,m)
        {
            int x,y,z,w;
            ret[i]=0;
            scanf("%d%d%d%d",&x,&y,&z,&w);
            qu[++tot]=node{x,y,-i,z-1};
            qu[++tot]=node{x,y,i,w};
        }
        dfs_cl=0;
        dfs1(1,0);
        dfs2(1,0,1);
        sort(qu+1,qu+tot+1);
        sort(id+1,id+n+1,cmp);
        build(1,n,1);
        int now=1;
        rep(i,1,tot)
        {
            while(now<=n&&a[id[now]]<=qu[i].x)
            {
                upd(pos[id[now]],a[id[now]],1,n,1);
                ++now;
            }
            if(qu[i].id<0)ret[-qu[i].id]-=gao(qu[i].l,qu[i].r);
            else ret[qu[i].id]+=gao(qu[i].l,qu[i].r);
        }
        rep(i,1,m)printf("%lld%c",ret[i],i==m?‘\n‘:‘ ‘);
    }
    return 0;
}
时间: 2024-10-20 11:30:47

Ch’s gift的相关文章

hdu 6162 Ch’s gift(树链剖分+主席树)

题目链接:hdu 6162 Ch's gift 题意: 给你一棵树,树上每个点有一个权值,现在有m个询问,每次询问给你一个s,t,L,R,问你从s到t的路径上,权值在[L,R]内的总和为多少. 题解: 我感觉我写复杂了,用树链剖分来维护路径,然后用主席树来建立权值线段树乱搞. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);

hdu6162 Ch’s gift

地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=6162 题目: Ch's gift Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 526    Accepted Submission(s): 177 Problem Description Mr. Cui is working of

HDU 6162 Ch’s gift (树剖 + 离线线段树)

Ch’s gift Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 662    Accepted Submission(s): 229 Problem Description Mr. Cui is working off-campus and he misses his girl friend very much. After a wh

L - Ch’s gift HDU - 6162

Ch’s gift Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2534    Accepted Submission(s): 887 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6162 Problem Description Mr. Cui is working off-campu

HDU 6162 Ch’s gift (线段树+树链剖分)

题意:给定上一棵树,每个树的结点有一个权值,有 m 个询问,每次询问 s, t ,  a, b,问你从 s 到 t 这条路上,权值在 a 和 b 之间的和.(闭区间). 析:很明显的树链剖分,但是要用线段树来维护,首先先离线,然后按询问的 a 排序,每次把小于 a 的权值先更新上,然后再查询,这样就是区间求和了,算完小于a的,再算b的,最答案相减就好了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #inc

2017全国多校第9场

一.HDU-6162 Ch's gift 思路:只要把主席树节点统计个数的意义改为累计所管辖区间的和就行了.剩下的部分就是裸的树上主席树了. #include<bits/stdc++.h> using namespace std; #define MAXN 100010 #define LOGN 20 #define MAXQ 100010 #define LL long long typedef struct { int to, next; } Edge; LL v[MAXN], dv[MA

Codeforces 505 A Mr. Kitayuta&#39;s Gift【暴力】

题意:给出一个字符串,可以向该字符串的任意位置插入一个字母使其变成回文串 因为字符串的长度小于10,枚举插入的字母,和要插入的位置,再判断是否已经满足回文串 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath> 5 #include<stack> 6 #include<vector> 7 #include<map> 8

NOIP2017模拟赛 senior 6.29 T3 Gift(gift)

Description Input Output 这道题的难度相对来说并没有第二题恼火,但还是很难搞的. 那么这道题读完题目还是比较好看出这是一道背包的变形题. 因为每一份礼物都是取或者不取两个状态,所以,01背包好理解吧. 然后题目中说选到不能选为止,所以我们先将读入的礼物的价值排个序,然后从大到小我们去选取礼物,如果当前礼物价值大于剩余财富,那么我们就不能选了对吧. 于是就这样一层层的向下进行动归. 每一次我们处理当前层的DP数组,将答案加上上一层DP数组的值.这样我们就合理的处理完了整个D

Codeforces Round #286 (Div. 2)A. Mr. Kitayuta&#39;s Gift(暴力,string的应用)

由于字符串的长度很短,所以就暴力枚举每一个空每一个字母,出现行的就输出.这么简单的思路我居然没想到,临场想了很多,以为有什么技巧,越想越迷...是思维方式有问题,遇到问题先分析最简单粗暴的办法,然后一步一步的优化,不能盲目的想. 这道题要AC的快需要熟悉string的各种用法.这里做个简单总结:C++中string的常见用法. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstrin