CF_216_Div_2

比赛链接:http://codeforces.com/contest/369

369C - Valera and Elections

这是一个树上问题,用深搜,最开始贪心想得是只加叶子节点,找到一个叶子节点且从根1 ——》 叶子节点有problem edges,就把这个点加入,但后来一直WA,才发现时贪错了,找到的这个叶子节点不一定需要,所以要多记录点信息,参考别人的思想,就是标记每个点是不是需要修,如果一个更深的点需要修,则中间的就不需要了。

代码:

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

const int maxn = 1e5+10;

vector< pair<int,int> > G[maxn];
bool rep[maxn];

void dfs(int u,int fa,int bef)  //bef是从1->u距离u最近的需要修的点,不断更新就行,最开始dfs(1,-1,-1)中bef == 1的原因是一这个点一定不需要修。
{
    int sz = G[u].size();

    for(int i=0; i<sz; i++)
    {
        pair<int,int> my = G[u][i];
        if(my.first == fa) continue;

        if(my.second == 2)
        {
            rep[my.first] = true;
            rep[bef] = false;
            dfs(my.first,u,my.first);
        }
        else
            dfs(my.first,u,bef);
    }
}

int main()
{
    //freopen("E:\\acm\\input.txt","r",stdin);
    int n;
    cin>>n;
    for(int i=1; i<n; i++)
    {
        int x,y,t;
        scanf("%d %d %d",&x,&y,&t);

        G[x].push_back(make_pair(y,t));
        G[y].push_back(make_pair(x,t));
    }
    memset(rep,0,sizeof(rep));
    dfs(1,-1,1);

    int ans = 0;
    for(int i=1; i<=n; i++)
        if(rep[i]) ans++;
    cout<<ans<<endl;
    for(int i=1; i<=n; i++)
        if(rep[i]) cout<<i<<" ";
}
View Code

Tutorial里面的解法没看懂

369D - Valera and Fools

只要明白每个situation要么是a[i]到a[n]的连续数列,要么是一个数a[j]+a[i]到a[n]的连续数列,这样情况就少很多,了解了这个,就可以想到用宽搜了

代码:

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

const int maxn = 3050;

int p[maxn];
int sum[maxn];
bool head[maxn];
bool man[maxn];

struct Node
{
    int u,v;
    int round;
    Node(int u=0,int v=0,int round=0):  u(u), v(v), round(round) {}
};

int main()
{
   // freopen("E:\\acm\\input.txt","r",stdin);

    int n,k;
    cin>>n>>k;
    for(int i=1; i<=n; i++)
        cin>>p[i];
    sum[n+1] = 0;
    man[n+1] = 0;
    for(int i=n; i>=1; i--)
    {
        sum[i] = sum[i+1] + p[i];
        if(p[i]==100 || man[i+1]) man[i] = 1;
        else                      man[i] = 0;
    }


    memset(head,0,sizeof(head)); //标记一个连续数列,让它最多出现一次

    int ans = 1;
    head[1] = true;

    queue< Node > Q;
    Q.push(Node(1,2,0));

    while(!Q.empty())
    {
        Node my = Q.front(); Q.pop();

        if(my.round >= k) continue;
        int u = my.u;
        int v = my.v;

        if(u > n || v > n) continue;


        if(p[u] > 0 && !man[v])
        {
            ans ++;
            Q.push(Node(u,v+1,my.round+1));
        }
        if(sum[v] > 0 && p[u] != 100 && !head[v])
        {
            ans ++;
            head[v] = true;
            Q.push(Node(v,v+1,my.round+1));
        }
        if(p[u] > 0 && sum[v] > 0 && !head[v+1])
        {
            ans ++;
            head[v+1] = true;
            Q.push(Node(v+1,v+2,my.round+1));
        }
    }
    cout<<ans<<endl;
}
View Code

369E - Valera and Queries

一直没思路,后来看题解知道要有求答案补集,因为正着来区间重复计数很难避免,而反着就是求不与点相交的区间的个数,进一步就是求每一个询问相邻点中区间的个数

用树状数组计数就行

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define SHOW(x) { cerr << ">>> " << #x << " = " << x << endl; }

using namespace std;

const int maxn = 1e6+10;
const int MV = 1e6+1;

struct BIT
{
    int C[maxn];

    int lowbit(int x)
    {
        return x&(-x);
    }

    void init()
    {
        memset(C,0,sizeof(C));
    }

    void add(int x,int a)
    {
        while(x <= MV)
        {
            C[x] += a;
            x += lowbit(x);
        }
    }

    int sum(int x)
    {
        if(x == 0) return 0;
        int ret = 0;
        while(x > 0)
        {
            ret += C[x];
            x -= lowbit(x);
        }
        return ret;
    }
}bit;
//要求一个区间内的线段的个数

struct Node
{
    int l,r;
    int id;
    bool operator < (const Node& rhs) const
    {
        return r < rhs.r;
    }
}I[maxn/3],Q[2*maxn/3];   //就由于一个数组开错了啊
int ans[maxn/3];

int main()
{
    freopen("E:\\acm\\input.txt","r",stdin);
    int n,m;
    cin>>n>>m;  
    bit.init();

    for(int i=1; i<=n; i++)
    {
        scanf("%d %d",&I[i].l,&I[i].r);
    }

    int cnt = 0;
    for(int i=1; i<=m; i++)
    {
        int num;
        scanf("%d",&num);
        for(int j=1; j<=num; j++)
        {
            int p;
            scanf("%d",&p);

            Q[++cnt].id = i;

            if(j == 1)
                Q[cnt].l = 0;
            else
                Q[cnt].l = Q[cnt-1].r;

            Q[cnt].r = p;
        }
        Q[++cnt].id = i;
        Q[cnt].l = Q[cnt-1].r;
        Q[cnt].r = MV;
    }
    sort(I+1,I+n+1);
    sort(Q+1,Q+cnt+1);

    for(int i=1; i<=m; i++) ans[i] = n;

    int pv = 1;
    for(int i=1; i<=cnt; i++)
    {
        while(pv <= n && I[pv].r < Q[i].r)
        {
            bit.add(I[pv].l,1);
            pv++;
        }
        ans[Q[i].id] -= bit.sum(Q[i].r-1) - bit.sum(Q[i].l);
    }
    for(int i=1; i<=m; i++)
        printf("%d\n",ans[i]);
}
View Code

 

posted @ 2013-12-10 17:08  等待最好的两个人  阅读(346)  评论(0编辑  收藏  举报