顯示具有 SPOJ 標籤的文章。 顯示所有文章
顯示具有 SPOJ 標籤的文章。 顯示所有文章

2018年2月22日 星期四

(SPOJ) SHELF - Book Shelves

http://www.spoj.com/problems/SHELF/en/

快被搞死了XDD

這裡先假設a_i = h_i

可以發現,列出後的DP式子長這個樣子:dp_i = min(dp_j + max(a_j, a_{j+1}, ...... , a_i))

再藉由一個很 greedy的性質:dp值是會遞增的,後面的max(a_j, a_{j+1}, ........, a_i) 隨著j的增加是遞減的!

那,我們就可以對於每個max_a,存下最左邊的DP值(最好的解),並把這個東西丟進multiset裡面比較

有了一個新的a_i近來,我們就需要 "合併" 一些max_a!。

經由分析,可以發現:一個東西最多進去multiset兩次,理由是:被merge前一次,被merge後一次。

在想一想,就能寫出下面那噁心(?)的code了><


#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <cassert>
using namespace std;

typedef long long LL;
typedef pair<LL,LL> pii;
typedef pair<pii,LL> piii;

#define F first
#define S second
#define SZ(x) ((int)(x).size())

const int N = 1e5 + 6;

LL prew[N],preh[N];
LL dp[N];

int w[N],h[N];
LL a[N];

piii P(LL _a,LL _b,LL _c)
{
    return make_pair( make_pair(_a,_b),_c );
}

struct DisjointSet
{
    static const int N = 1e5 + 6;
    int p[N];
    int sz[N];
    int max_a[N];
    int left_most[N];
    void init(int n)
    {
        for (int i=0;n>=i;i++)
        {
            p[i] = i;
            sz[i] = 1;
        }
    }
    int Find(int x)
    {
        return p[x] == x?x:p[x] = Find(p[x]);
    }
    void set_a(int pos,int val)
    {
        pos = Find(pos);
        max_a[pos] = val;
    }
    void set_left_most(int pos,int val)
    {
        pos = Find(pos);
        left_most[pos] = val;
    }
    void Union(int x,int y)
    {
        x = Find(x);
        y = Find(y);
        if (x == y) return;
        if (sz[x] > sz[y]) swap(x,y);
        //x has smaller size
        max_a[y] = max(max_a[y],max_a[x]);
        left_most[y] = min(left_most[x],left_most[y]);
        sz[y] += sz[x];
        p[x] = y;
    }
    int query_max_a(int x)
    {
        x = Find(x);
        return max_a[x];
    }
    int query_left_most(int x)
    {
        x = Find(x);
        return left_most[x];
    }
} djs;

int main ()
{
    int n,l;
    scanf("%d %d",&n,&l);
    for (int i=1;n>=i;i++)
    {
        scanf("%d %d",&h[i],&w[i]);
        preh[i] = preh[i-1] + h[i];
        prew[i] = prew[i-1] + w[i];
        a[i] = h[i];
    }
    deque<int> dq;  // index
    multiset<LL> st;
    djs.init(n);
    int dead_end = 0;
    for (int i=1;n>=i;i++)
    {
        //popping XDD
        while (SZ(dq))
        {
            int t=dq.front();
            if (prew[i] - prew[t-1] <= l) break;
            dead_end = t;
            dq.pop_front();
            if (st.find(dp[t-1] + djs.query_max_a(t)) == st.end()) assert(0);
            st.erase(st.find(dp[t-1] + djs.query_max_a(t)));
            if (djs.Find(t+1) == djs.Find(t))
            {
                st.insert(dp[t+1-1] + djs.query_max_a(t+1));
                djs.set_left_most(t+1,t+1);
            }
        }
        //inserting
        djs.set_a(i,a[i]);
        djs.set_left_most(i,i);
        for (int t=i-1;t != dead_end;)
        {
            if (djs.query_max_a(t) > djs.query_max_a(i)) break;
            int left = djs.query_left_most(t);
            if (st.find(dp[left-1] + djs.query_max_a(left)) == st.end()) assert(0);
            st.erase(st.find(dp[left-1] + djs.query_max_a(left)));
            djs.Union(i,left);
            t = left-1;
        }
        dq.push_back(i);
        int ll=djs.query_left_most(i);
        st.insert(dp[ll-1] + djs.query_max_a(ll));
        dp[i] = (*st.begin());
    }
    printf("%lld\n",dp[n]);
}

2017年4月12日 星期三

(SPOJ) RPLN - Negative Score [Sparse-Table]

http://www.spoj.com/problems/RPLN/

implement with sparse table

<O(n lg n), O(1)>

//use sparse table
#include <iostream>
#include <stdio.h>
using namespace std;

const int MAX_N = 1e5 +6;
const int MAX_P = 18;

int a[MAX_N];
int st[MAX_P][MAX_N];
int lg2[MAX_N];
int pow2[MAX_P];

int main () {
    pow2[0]=1;
    for (int i=1;MAX_P>i;i++) {
        pow2[i] = pow2[i-1]*2;
    }
    lg2[1] = 0;
    int id=1;
    for (int i=2;MAX_N>i;i++) {
        if (i==pow2[id]) {
            lg2[i] = lg2[i-1]+1;
            id++;
        }
        else {
            lg2[i] = lg2[i-1];
        }
    }
    int T;
    scanf("%d",&T);
    int cases=0;
    while (T--) {
        int n,q;
        scanf("%d %d",&n,&q);
        for (int i=1;n>=i;i++) {
            scanf("%d",&a[i]);
            st[0][i] = a[i];
        }
        for (int i=1;MAX_P>i;i++) {
            for (int j=1;n>=j;j++) {
                int r=j+pow2[i-1];
                if (r>n) r=n;
                st[i][j] = min(st[i-1][j],st[i-1][r]);
            }
        }
        printf("Scenario #%d:\n",++cases);
        while (q--) {
            int l,r;
            scanf("%d %d",&l,&r);
            int dis=(r-l+1);
            printf("%d\n",min(st[lg2[dis]][l],st[lg2[dis]][r-pow2[lg2[dis]]+1]));
        }
    }
}


2017年3月8日 星期三

(SPOJ) QTREE - Query on a tree [樹鍊剖分]

http://www.spoj.com/problems/QTREE/

樹鍊剖分

不過在TOJ上面的卻TLE了QQ

#include <iostream>
#include <stdio.h>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAX_N = 1e5 +6;
const int MAX_P = 17;

vector<int> edg[MAX_N];
int seg[4*MAX_N];
int val[MAX_N];

void init(int id,int L,int R) {
    if (L==R) {
        seg[id] = val[L];
        return;
    }
    int mid=(L+R)>>1;
    init(id*2,L,mid);
    init(id*2+1,mid+1,R);
    seg[id] = max(seg[id*2],seg[id*2+1]);
    return;
}

void modify(int id,int L,int R,int pos,int val) {
    if (L==R) {
        seg[id] = val;
        return;
    }
    int mid=(L+R)>>1;
    if (pos <= mid) modify(id*2,L,mid,pos,val);
    else modify(id*2+1,mid+1,R,pos,val);
    seg[id] = max(seg[id*2],seg[id*2+1]);
    return;
}

int query(int id,int L,int R,int l,int r) {
    if (l>R || L>r) return 0;
    else if (l<=L && R<=r) return seg[id];
    int mid=(L+R)>>1;
    return max(query(id*2,L,mid,l,r),query(id*2+1,mid+1,R,l,r));
}

struct Edge {
    int a,b,c;
    void input() {
        scanf("%d %d %d",&a,&b,&c);
    }
} edge[MAX_N];

int sz[MAX_N];
bool visit[MAX_N];
int par[MAX_P][MAX_N];

void dfs1(int id,int p) {
    par[0][id] = p;
    sz[id] = 1;
    visit[id] = 1;
    for (auto i:edg[id]) {
        if (!visit[i]) {
            dfs1(i,id);
            sz[id] += sz[i];
        }
    }
}

int tin[MAX_N],tout[MAX_N];
int ttin[MAX_N];
int head[MAX_N];
int stamp1,stamp2;
int depth[MAX_N];

void dfs2(int id,int headd,int cur_depth) {
    ttin[id] = stamp1;
    tin[id] = stamp2;
    stamp1++;
    stamp2++;
    visit[id]=1;
    head[id] = headd;
    depth[id] = cur_depth;
    sort(edg[id].begin(),edg[id].end(),[](int &a,int &b) {
        return sz[a] > sz[b];
    });
    bool flag=false;
    for (auto i:edg[id]) {
        if (!visit[i]) {
            if (!flag) {
                dfs2(i,headd,cur_depth+1);
                flag=1;
            }
            else {
                dfs2(i,i,cur_depth+1);
            }
        }
    }
    tout[id]=stamp2;
    stamp2++;
}

bool is_anc(int son,int parent) {
    return tin[son]>=tin[parent] && tout[parent]>=tout[son];
}

int get_real_lca(int x,int y) {
    if (depth[x] > depth[y]) swap(x,y);
    if (is_anc(y,x)) return x;
    for (int i=MAX_P-1;i>=0;i--) {
        if (!is_anc(x,par[i][y])) y=par[i][y];
    }
    return par[0][y];
}

int get_fake_lca(int parent,int son) {
    if (parent == son) return 0;
    for (int i=MAX_P-1;i>=0;i--) {
        if (!is_anc(parent,par[i][son])) {
            son = par[i][son];
        }
    }
    return son;
}

int main () {
    int T;
    scanf("%d",&T);
    while (T--) {
        int n;
        scanf("%d",&n);
        for (int i=0;n>=i;i++) {
            edg[i].clear();
        }
        for (int i=1;n>i;i++) {
            edge[i].input();
            edg[edge[i].a].push_back(edge[i].b);
            edg[edge[i].b].push_back(edge[i].a);
        }
        memset(visit,0,sizeof(visit));
        dfs1(1,1);
        memset(visit,0,sizeof(visit));
        stamp1=stamp2=1;
        dfs2(1,1,1);
        for (int i=1;n>i;i++) {
            int &_a=edge[i].a,&_b=edge[i].b,_c=edge[i].c;
            if (ttin[_a] > ttin[_b]) swap(_a,_b);
            val[ttin[_b]] = _c;
        }
        val[1] = 0;
        init(1,1,n);
        for (int i=1;MAX_P>i;i++) {
            for (int j=1;n>=j;j++) {
                par[i][j] = par[i-1][par[i-1][j]];
            }
        }
        char s[10];
        while (1) {
            getchar();
            scanf("%s",s);
            if (s[0]=='D') {
                //huuray!!!
                break;
            }
            else if (s[0]=='C') {
                int a,b;
                scanf("%d %d",&a,&b);
                modify(1,1,n,ttin[edge[a].b],b);
            }
            else {
                int a,b;
                scanf("%d %d",&a,&b);
                if (depth[a] > depth[b]) swap(a,b);
                int lca=get_real_lca(a,b);
                if (a==b) {
                    puts("0");
                    continue;
                }
                int destination=get_fake_lca(lca,b);
                int ans=0;
                while (depth[destination] <= depth[b]) {
                    if (depth[head[b]] >= depth[destination]) {
                        ans = max(ans,query(1,1,n,ttin[head[b]],ttin[b]));
                        b=head[b];
                        b=par[0][b];
                    }
                    else {
                        ans = max(ans,query(1,1,n,ttin[destination],ttin[b]));
                        break;
                    }
                }
                if (lca != a) {
                    destination = get_fake_lca(lca,a);
                    b=a;
                    while (depth[destination] <= depth[b]) {
                        if (depth[head[b]] >= depth[destination]) {
                            ans = max(ans,query(1,1,n,ttin[head[b]],ttin[b]));
                            b=head[b];
                            b=par[0][b];
                        }
                        else {
                            ans = max(ans,query(1,1,n,ttin[destination],ttin[b]));
                            break;
                        }
                    }
                }
                printf("%d\n",ans);
            }
        }
    }
}

2017年2月19日 星期日

(SPOJ) GSS3 - Can you answer these queries III

http://www.spoj.com/problems/GSS3/


#include <iostream>
#include <stdio.h>
#include <ctime>
#include <cstdlib>
using namespace std;

typedef long long LL;
const LL INF = 1e15 + 6;

struct Treap {
    Treap *lc,*rc;
    LL val;
    LL key;
    LL lmax,rmax,midmax,sum;
    int pri;
    Treap(LL _key,LL _val) {
        lc=rc=NULL;
        pri = rand();
        lmax=rmax=midmax=sum=val=_val;
        key = _key;
    }
};

LL Lmax(Treap* t) {
    return t?t->lmax:-INF;
}

LL Rmax(Treap* t) {
    return t?t->rmax:-INF;
}

LL Midmax(Treap* t) {
    return t?t->midmax:-INF;
}

LL Sum(Treap* t) {
    return t?t->sum:0;
}

void pull(Treap* t) {
    t->sum = Sum(t->lc) + Sum(t->rc) + t->val;
    t->lmax = max(max(Lmax(t->lc),Sum(t->lc)+t->val),Sum(t->lc)+t->val+Lmax(t->rc));
    t->rmax = max(max(Rmax(t->rc),Sum(t->rc)+t->val),Sum(t->rc)+t->val+Rmax(t->lc));
    t->midmax = max(max(max(Midmax(t->lc),Midmax(t->rc)),t->val),max(max(Rmax(t->lc)+t->val,Lmax(t->rc)+t->val),Lmax(t->rc)+Rmax(t->lc)+t->val));
}

Treap* merge(Treap* a,Treap* b) {
    if (!a || !b) return a?a:b;
    else if (a->pri > b->pri) {
        a->rc=merge(a->rc,b);
        pull(a);
        return a;
    }
    else {
        b->lc=merge(a,b->lc);
        pull(b);
        return b;
    }
}

void split(Treap* t,LL k,Treap* &a,Treap* &b) {
    if (!t) a=b=NULL;
    else if (t->key <= k) {
        a=t;
        split(t->rc,k,a->rc,b);
        pull(a);
    }
    else {
        b=t;
        split(t->lc,k,a,b->lc);
        pull(b);
    }
}

const int MAX_N = 5e4 + 6;

LL a[MAX_N];

int main () {
    int n;
    while (scanf("%d",&n) != EOF) {
        Treap* root;
        root=NULL;
        for (int i=1;n>=i;i++) {
            scanf("%lld",&a[i]);
            root = merge(root,new Treap(i,a[i]));
        }
        int m;
        scanf("%d",&m);
        while (m--) {
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            if (a==0) {
                Treap *tl,*tr;
                split(root,b-1,tl,root);
                split(root,b,root,tr);
                root = merge(merge(tl,new Treap(b,c)),tr);
            }
            else {
                Treap *tl,*tr;
                split(root,b-1,tl,root);
                split(root,c,root,tr);
                printf("%lld\n",root->midmax);
                root=merge(merge(tl,root),tr);
            }
        }
    }
}