`
java-mans
  • 浏览: 11339524 次
文章分类
社区版块
存档分类
最新评论

POJ 3145 HDU 3303 Harmony Forever 线段树 + 鸽巢定理

 
阅读更多

大意就是对一个集合,有两种操作,一个是将某个元素加入集合中,一个是问当前集合中mod y 最小的数,如果有多个,输出最近加入的那个元素,当然题目要求的是输出他们加入集合的时间是什么。


题目的数据范围一看就是线段树类型的。

然后对每个y,由鸽巢定理,y+1个数中必然存在mod y相同的数,那么分为多个区间进行查询,即[0, y - 1] [y , 2 * y - 1]…… 然后取最优解即可

但是这样可能会退化,当y等于1的时候就发现,要查询50W个区间,每次查询都是log(n)级别,还不如直接遍历当前序列效率高,因为序列最多也就4W个数据。

所以可以推测,当y比较小的时候,直接遍历会更快。

实际上离散化会更靠谱,因为只有4W个数据,然后建树查询的时候就方便多了 ,经过验证,离散前是1360ms,离散化后就成800多ms了,瞬间进前5

/*
ID: sdj22251
PROG: subset
LANG: C++
*/
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 510005
#define MAXM 164444
#define INF 100000000
#define eps 1e-7
#define L(X) X<<1
#define R(X) X<<1|1
using namespace std;
struct node
{
    int left, right;
    int mi;
}tree[4 * MAXN];
int a[MAXN], pos[MAXN];
void up(int C)
{
    tree[C].mi = min(tree[L(C)].mi, tree[R(C)].mi);
}
void make_tree(int s, int e, int C)
{
    tree[C].left = s;
    tree[C].right = e;
    tree[C].mi = INF;
    if(s == e) return;
    int mid = (s + e) >> 1;
    make_tree(s, mid, L(C));
    make_tree(mid + 1, e, R(C));
}
void update(int p, int C)
{
    if(tree[C].left == tree[C].right)
    {
        tree[C].mi = p;
        return;
    }
    int mid = (tree[C].left + tree[C].right) >> 1;
    if(mid >= p) update(p, L(C));
    else update(p, R(C));
    up(C);
}
int ans;
void query(int s, int e, int C)
{
    if(tree[C].left >= s && tree[C].right <= e)
    {
        ans = min(ans, tree[C].mi);
        return;
    }
    int mid = (tree[C].left + tree[C].right) >> 1;
    if(mid >= s) query(s, e, L(C));
    if(mid < e) query(s, e, R(C));
}
int in()
{
    int flag = 1;
    char ch;
    int a = 0;
    while((ch = getchar()) == ' ' || ch == '\n');
    if(ch == '-') flag = -1;
    else
    a += ch - '0';
    while((ch = getchar()) != ' ' && ch != '\n')
    {
        a *= 10;
        a += ch - '0';
    }
    return flag * a;
}
void out(int a)
{
    if(a >= 10)out(a / 10);
    putchar(a % 10 + '0');
}
int main()
{
    int t, x, cas = 0;
    char s;
    while(scanf("%d", &t) != EOF && t)
    {
        if(cas) puts("");
        int cnt = 0;
        memset(pos, -1, sizeof(pos));
        printf("Case %d:\n", ++cas);
        make_tree(1, MAXN - 1, 1);
        getchar();
        while(t--)
        {
            s = getchar();
            x = in();
            if(s == 'A')
            {

                if(x < 5000)
                {
                    ans = INF;
                    int tx = x;
                    for(int i = cnt - 1; i >= 0; i--)
                    {
                        if(a[i] % x < tx)
                        {
                            tx = a[i] % x;
                            ans = a[i];
                        }
                        if(tx == 0) break;
                    }
                    if(ans == INF) {puts("-1");}
                    else {out(pos[ans] + 1); putchar('\n');}
                }
                else
                {
                    int bd = 500055 / x;
                    int res = INF;
                    int tx = x;
                    for(int i = 0; i <= bd; i++)
                    {
                        ans = INF;
                        int low = i * x;
                        if(low < 1) low = 1;
                        int high = (i + 1) * x - 1;
                        if(high > 500054) high = 500054;
                        query(low, high, 1);
                        if(ans == INF) continue;
                        if(ans % x < tx)
                        {
                            tx = ans % x;
                            res = ans;
                        }
                        else if(ans % x == tx)
                        {
                            if(pos[ans] > pos[res]) res = ans;
                        }
                    }
                    if(res == INF) {puts("-1");}
                    else {out(pos[res] + 1); putchar('\n');}
                }
            }
            else
            {
                if(pos[x] == -1)
                {
                    pos[x] = cnt;
                    a[cnt++] = x;
                    update(x, 1);
                }
            }
        }
    }
    return 0;
}


然后是离散化版本的,速度快了许多啊


/*
ID: sdj22251
PROG: subset
LANG: C++
*/
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define MAXN 45555
#define MAXM 164444
#define INF 100000000
#define eps 1e-7
#define L(X) X<<1
#define R(X) X<<1|1
using namespace std;
struct node
{
    int left, right;
    int mi;
}tree[4 * MAXN];
int a[MAXN], pos[555555], x[MAXN], ax[MAXN];
void up(int C)
{
    tree[C].mi = min(tree[L(C)].mi, tree[R(C)].mi);
}
void make_tree(int s, int e, int C)
{
    tree[C].left = s;
    tree[C].right = e;
    tree[C].mi = INF;
    if(s == e) return;
    int mid = (s + e) >> 1;
    make_tree(s, mid, L(C));
    make_tree(mid + 1, e, R(C));
}
void update(int p, int C)
{
    if(tree[C].left == tree[C].right)
    {
        tree[C].mi = x[p];
        return;
    }
    int mid = (tree[C].left + tree[C].right) >> 1;
    if(mid >= p) update(p, L(C));
    else update(p, R(C));
    up(C);
}
int ans;
void query(int s, int e, int C)
{
    if(tree[C].left >= s && tree[C].right <= e)
    {
        ans = min(ans, tree[C].mi);
        return;
    }
    int mid = (tree[C].left + tree[C].right) >> 1;
    if(mid >= s) query(s, e, L(C));
    if(mid < e) query(s, e, R(C));
}
int in()
{
    int flag = 1;
    char ch;
    int a = 0;
    while((ch = getchar()) == ' ' || ch == '\n');
    if(ch == '-') flag = -1;
    else
    a += ch - '0';
    while((ch = getchar()) != ' ' && ch != '\n')
    {
        a *= 10;
        a += ch - '0';
    }
    return flag * a;
}
void out(int a)
{
    if(a >= 10)out(a / 10);
    putchar(a % 10 + '0');
}
int bin(int v, int bound)
{
    int low = 0, high = bound - 1, mid;
    while(low <= high)
    {
        mid = (low + high) >> 1;
        if(x[mid] == v) return mid;
        if(x[mid] < v) low = mid + 1;
        else high = mid - 1;
    }
    return high;
}
char s[40005];
int main()
{
    int t, cas = 0;
    while(scanf("%d", &t) != EOF && t)
    {
        if(cas) puts("");
        int cnt = 0;
        memset(pos, -1, sizeof(pos));
        printf("Case %d:\n", ++cas);
        int nt = 0;
        getchar();
        for(int i = 0; i < t; i++)
        {
            s[i] = getchar();
            ax[i] = in();
            if(s[i] == 'B') x[nt++] = ax[i];
        }
        x[nt++] = 1;
        x[nt++] = 500100;
        sort(x, x + nt);
        nt = unique(x, x + nt) - x;
        make_tree(0, nt - 1, 1);
        for(int i = 0; i < t; i++)
        {
            if(s[i] == 'A')
            {
                if(ax[i] < 500)
                {
                    ans = INF;
                    int tx = ax[i];
                    for(int j = cnt - 1; j >= 0; j--)
                    {
                        if(a[j] % ax[i] < tx)
                        {
                            tx = a[j] % ax[i];
                            ans = a[j];
                        }
                        if(tx == 0) break;
                    }
                    if(ans == INF) {puts("-1");}
                    else {out(pos[ans] + 1); putchar('\n');}
                }
                else
                {
                    int bd = 500055 / ax[i];
                    int res = INF;
                    int tx = ax[i];
                    for(int j = 0; j <= bd; j++)
                    {
                        ans = INF;
                        int low = j * ax[i];
                        if(low < 1) low = 1;
                        int high = (j + 1) * ax[i] - 1;
                        if(high > 500054) high = 500054;
                        int ll = bin(low, nt);
                        int rr = bin(high, nt);
                        if(x[ll] < low) ll++;
                        if(ll > rr) continue;
                        query(ll, rr, 1);
                        if(ans == INF) continue;
                        if(ans % ax[i] < tx)
                        {
                            tx = ans % ax[i];
                            res = ans;
                        }
                        else if(ans % ax[i] == tx)
                        {
                            if(pos[ans] > pos[res]) res = ans;
                        }
                    }
                    if(res == INF) {puts("-1");}
                    else {out(pos[res] + 1); putchar('\n');}
                }
            }
            else
            {
                if(pos[ax[i]] == -1)
                {
                    pos[ax[i]] = cnt;
                    a[cnt++] = ax[i];
                    int l = bin(ax[i], nt);
                    update(l, 1);
                }
            }
        }
    }
    return 0;
}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics