2019DX#3

Solved Pro.ID Title Ratio(Accepted / Submitted)
  1001 Azshara's deep sea        凸包 6.67%(6/90)
 👌 1002 Blow up the city                          反向边,支配树思想,u有多个父节点,直接连向他们的lca 31.19%(126/404)
  1003 Yukikaze and Demons        分治 16.67%(4/24)
👌 1004 Distribution of books       二分+dp检查+数据结构优化 19.29%(93/482)
  1005 Easy Math Problem         Min25筛,杜教筛 9.30%(4/43)
  1006 Fansblog 21.17%(671/3170)
  1007 Find the answer 11.24%(508/4521)
 ok 1008 Game              带修莫队 16.08%(23/143)
 👌 1009 K Subsequence        优秀建图或者DJI版费用流,卡spfa 5.81%(87/1497)
  1010 Sindar's Art Exhibition      树链剖分 24.66%(18/73)
👌  1011 Squrirrel            换根树形DP,注意细节 13.86%(46/332)

1002 Blow up the city

支配树的思想,u有多个父节点,直接连向他们的lca

#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>
// #include<bits/extc++.h>
// using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define fi first
#define se second
#define debug(x) cerr<<#x << " := " << x << endl;
#define bug cerr<<"-----------------------"<<endl;
#define FOR(a, b, c) for(int a = b; a <= c; ++ a)

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
/**********showtime************/
            const int maxn = 1e5+9;
            vector<int>mp[maxn],g[maxn];
            int du[maxn];
            int dp[maxn];
            int fa[maxn][20];
            int lca(int x, int y){
                if(dp[x] < dp[y]) swap(x, y);
                for(int i=19; i>=0; i--){
                    if(dp[y] <= dp[fa[x][i]]){
                        x = fa[x][i];
                    } 
                }
                if(x == y) return x;
                for(int i=19; i>=0; i--){
                    if(fa[x][i] != fa[y][i]){
                        x = fa[x][i];
                        y = fa[y][i];
                    }
                }
                return fa[x][0];
            }

            void bfs(int s) {
                queue<int>que;
                que.push(s);
                while(!que.empty()) {
                    int u = que.front();que.pop();
                    for(int i=0; i<mp[u].size(); i++) {
                        int v = mp[u][i];
                        du[v]--;
                        if(du[v] == 0) {
                            int p = g[v][0];

                            for(int j=1; j<g[v].size(); j++){
                                int a = g[v][j];
                                p = lca(p, a);
                            }
                            fa[v][0] = p;
                            for(int i=1; i<20; i++)
                                fa[v][i] = fa[fa[v][i-1]][i-1];
                            dp[v] = dp[p]+1;
                            que.push(v);
                        }
                    }
                }   
            }
int main(){
            int T;  scanf("%d", &T);
            while(T--){
                int n,m;
                scanf("%d%d", &n, &m);
                for(int i=0; i<=n; i++) mp[i].clear(), du[i] = 0,g[i].clear(),dp[i] = 0;
                for(int i=1; i<=m; i++) {
                    int u,v;
                    scanf("%d%d", &u, &v);
                    mp[v].pb(u);
                    g[u].pb(v);
                    du[u]++;
                }
                int rt = 0;
                for(int i=1; i<=n; i++) {
                    if(du[i]) continue;
                    mp[rt].pb(i);
                    g[i].pb(rt);
                    du[i]++;
                }
                bfs(rt);

                int q;  scanf("%d", &q);
                while(q--) {
                    int a,b;
                    scanf("%d%d", &a, &b);
                    int l = lca(a, b);
                    printf("%d\n", dp[a] + dp[b] - dp[l]);
                }
            }   

            return 0;
}
View Code

 

1004 Distribution of books

二分答案x

dp[]表示前i个在满足每段sum<=x的情况下最多分成几段。

转移dp[i] = max(dp[j] + 1), 要求sum[i] - sum[j] <= x

我是用线段树优化的

#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>
// #include<bits/extc++.h>
// using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define fi first
#define se second
#define debug(x) cerr<<#x << " := " << x << endl;
#define bug cerr<<"-----------------------"<<endl;
#define FOR(a, b, c) for(int a = b; a <= c; ++ a)

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
/**********showtime************/

            const int maxn = 2e5+9;
            int a[maxn];
            ll sum[maxn];
            int n,m;
            vector<ll>v;
            int getid(ll x){
                return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
            }

            int mx[(maxn * 2) << 2];
            void build(int le, int ri, int rt) {
                if(le == ri) {
                    mx[rt] = -inf;
                    return;
                }
                int mid = (le + ri) >> 1;
                build(le, mid, rt<<1);
                build(mid+1, ri, rt<<1|1);
                mx[rt] = max(mx[rt<<1], mx[rt<<1|1]);
            }
            void update(int pos, int val, int le, int ri, int rt){
                if(le == ri) {
                    mx[rt] = max(mx[rt], val);
                    return;
                }
                int mid = (le + ri) >> 1;
                if(pos <= mid) update(pos, val, le, mid, rt<<1);
                else update(pos, val, mid+1, ri, rt<<1|1);
                mx[rt] = max(mx[rt<<1], mx[rt<<1|1]);
            }
            int query(int L, int R, int le, int ri, int rt) {
                if(le >= L && ri <= R) {
                    return mx[rt];
                }
                int mid = (le + ri) >> 1;
                int res = -inf;
                if(mid >= L) res = max(res, query(L, R, le, mid, rt<<1));
                if(mid < R) res = max(res, query(L, R, mid+1, ri, rt<<1|1));
                return res;
            }
            bool check(ll ss) {
                v.clear();
                v.pb(0);
                for(int i=1; i<=n; i++) {v.pb(sum[i]);v.pb(sum[i] - ss);}
                sort(v.begin(), v.end());
                v.erase(unique(v.begin(), v.end()), v.end());
                int N = v.size();
                build(1, N, 1);
                update(getid(0), 0, 1, N, 1);
                for(int i=1; i<=n; i++) {
                    int le = getid(sum[i] - ss);
                    int q = query(le, N, 1, N, 1) + 1;
                    if(q >= m) return true;
                    update(getid(sum[i]), q, 1, N, 1);
                }
                return false;
            }
int main(){
            int T;  scanf("%d", &T);
            while(T--){
                scanf("%d%d", &n, &m);
                ll le = 0, ri = 0;
                for(int i=1; i<=n; i++) {
                    scanf("%d", &a[i]);
                    sum[i] = sum[i-1] + a[i];
                    if(a[i] < 0) le += a[i];
                    ri = max(ri, 1ll*a[i]);
                }
                ll res;

                while(le <= ri) {
                    ll mid = (le + ri) >> 1;
                    if(check(mid)) ri = mid-1, res = mid;
                    else le = mid+1;
                }
                printf("%lld\n", res);
            }
            return 0;
}
/*
1
5 4
1 1 1 -5 1
*/
View Code

 

1008 Game

问题:是问区间$[L, R]$间,有多少子区间的异或和不为0.

我们求出前缀异或和,问题就转化为了区间中值相同的对数.

由于带修改,就转化为了带修改的莫队。

#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>
#include <unordered_map>
// #include<bits/extc++.h>
// using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define fi first
#define se second
#define debug(x) cerr<<#x << " := " << x << endl;
#define bug cerr<<"-----------------------"<<endl;
#define FOR(a, b, c) for(int a = b; a <= c; ++ a)

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;

template<typename T>
inline T read(T&x){
    x=0;int f=0;char ch=getchar();
    while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x=f?-x:x;
}
/**********showtime************/
            const int maxn = 1e5+9;
            int a[maxn], yuan[maxn];
            int numsum[maxn];
            struct Query{
                int le, ri;
                int lb, rb;
                int tim;
                int id;
            } que[maxn];
            struct Edit{
                int pos;
                int preval, nxtval;
            } edit[maxn * 2];
            bool cmp(Query a, Query b) {
                if(a.lb != b.lb) {
                    return a.lb < b.lb;
                }
                if(a.rb != b.rb) {
                    return a.rb < b.rb;
                }
                return a.tim < b.tim;
            }
            ll ans[maxn], pre[maxn];
            const int N = 2e6+9;
            int cnt[N];
            ll sum = 0;
            void add(int pos) {
                int val = numsum[pos];
                sum -= pre[cnt[val]];
                cnt[val] ++;
                sum += pre[cnt[val]];
            }
            void del(int pos) {
                int val = numsum[pos];
                sum -= pre[cnt[val]];
                cnt[val]--;
                sum += pre[cnt[val]];
            }
            ///时间增长
            void up(int tt, int le, int ri) {
                int pos = edit[tt].pos;
                if(pos >= le && pos <= ri) {
                     int val = numsum[pos];
                     sum -= pre[cnt[val]];
                     cnt[val] --;
                     sum += pre[cnt[val]];

                     numsum[pos] = edit[tt].nxtval;
                     val = numsum[pos];
                     sum -= pre[cnt[val]];
                     cnt[val]++;
                     sum += pre[cnt[val]];
                }
                else {
                    numsum[pos] = edit[tt].nxtval;
                }
            }
            ///时间回退
            void down(int tt, int le, int ri) {
                int pos = edit[tt].pos;
                if(pos >= le && pos <= ri) {
                     int val = numsum[pos];
                     sum -= pre[cnt[val]];
                     cnt[val] --;
                     sum += pre[cnt[val]];

                     numsum[pos] = edit[tt].preval;
                     val = numsum[pos];
                     sum -= pre[cnt[val]];
                     cnt[val]++;
                     sum += pre[cnt[val]];
                }
                else {
                    numsum[pos] = edit[tt].preval;
                }
            }
int main(){
            int n,m;
            for(int i=2; i<maxn; i++) {
                pre[i] = pre[i-1] + i - 1;
            }
            while(~scanf("%d%d", &n, &m)){
                for(int i=1; i<=n; i++) scanf("%d", &a[i]), yuan[i] = a[i];
                for(int i=1; i<=n; i++) numsum[i] = numsum[i-1] ^ a[i];
                int qtot = 0, etot = 0;
                int block = 5000;//pow(n * m , 1.0/3)+1;
                for(int i=1; i<=m; i++) {
                    int op; scanf("%d", &op);
                    if(op == 1) {
                        qtot++;
                        scanf("%d%d", &que[qtot].le, &que[qtot].ri);
                        que[qtot].le--;
                        que[qtot].lb = que[qtot].le / block;
                        que[qtot].rb = que[qtot].ri / block;
                        que[qtot].tim = etot;
                        que[qtot].id = qtot;
                    }
                    else {
                        etot++;
                        int pos;    scanf("%d", &pos);
                        edit[etot].pos = pos;
                        edit[etot].preval = numsum[pos];
                        edit[etot].nxtval = numsum[pos + 1] ^ yuan[pos];

                        etot++;
                        edit[etot].pos = pos + 1;
                        edit[etot].preval = numsum[pos+1];
                        edit[etot].nxtval = numsum[pos+1];

                        numsum[pos] = numsum[pos + 1] ^ yuan[pos];
                        swap(yuan[pos], yuan[pos+1]);
                    }
                }

                sort(que+1, que+1+qtot, cmp);
                for(int i=0; i<N; i++) cnt[i] = 0;
                for(int i=1; i<=n; i++) numsum[i] = numsum[i-1] ^ a[i];

                int le = 0, ri = 0;
                int cur = 0;
                cnt[0] = 1;
                sum = 0;
                for(int i=1; i<=qtot; i++) {
                    while(le < que[i].le) del(le), le++;
                    while(le > que[i].le) le--, add(le);
                    while(ri < que[i].ri) ri++, add(ri);
                    while(ri > que[i].ri) del(ri), ri--;
                    while(cur < que[i].tim) cur++,up(cur, le, ri);
                    while(cur > que[i].tim) down(cur, le, ri), cur--;
                    ans[que[i].id] = pre[que[i].ri - que[i].le + 1] - sum;
                }
                for(int i=1; i<=qtot; i++) printf("%lld\n", ans[i]);
            }
            return 0;
}
View Code

 

 

1009 K Subsequence

卡了spfa,其他没了

#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>

using namespace std;

const int inf = 0x3f3f3f3f;

const int mod = 998244353;
typedef long long ll;
typedef pair<int,int>pii;
#define pb push_back
#define fi first
#define se second
/**********showtime************/
                const int N = 4000 + 10;
                const int INF = 0x3f3f3f3f;

                struct edge {
                    int to, cap, cost, rev;
                    edge(int t, int c, int co,int re){
                        to = t;cap = c; cost = co; rev = re;
                    }
                };
                int V;
                vector<edge>g[N];
                int h[N], dis[N], prevv[N], preve[N];
                void addedge(int u, int v, int cap, int cost) {
                    g[u].pb(edge(v, cap, cost, g[v].size()));
                    g[v].pb(edge(u, 0, -cost, g[u].size()-1));
                }

                int solve(int s, int t, int f) {
                    int res = 0;
                    memset(h, 0, sizeof(h));
                    while(f > 0) {
                        priority_queue<pii, vector<pii>, greater<pii> > q;
                        memset(dis, inf, sizeof(dis));
                        dis[s] = 0;
                        q.push(pii(0, s));
                        while(!q.empty()) {
                            pii p = q.top();
                            q.pop();
                            int v = p.se;
                            if(dis[v] < p.fi) continue;
                            for (int i = 0; i < g[v].size(); ++i) {
                                edge &e = g[v][i];
                                if(e.cap > 0 && dis[e.to] > dis[v] + e.cost + h[v] - h[e.to]) {
                                    dis[e.to] = dis[v] + e.cost + h[v] - h[e.to];
                                    prevv[e.to] = v;
                                    preve[e.to] = i;
                                    q.push(pii(dis[e.to], e.to));
                                }
                            }
                        }
                        if(dis[t] == INF) return -1;
                        for (int v = 0; v < V; ++v) h[v] += dis[v];
                        int d = f;
                        for (int v = t; v != s; v = prevv[v]) d = min(d, g[prevv[v]][preve[v]].cap);
                        f -= d;
                        res += d*h[t];
                        for (int v = t; v != s; v = prevv[v]) {
                            edge &e = g[prevv[v]][preve[v]];
                            e.cap -= d;
                            g[v][e.rev].cap += d;
                        }
                    }
                    return res;
                }
                const int maxn = 2e3+9;
                int a[maxn];
int main(){
            int T;  scanf("%d", &T);
            while(T--) {
                int n,k;
                scanf("%d%d", &n, &k);

                int s = 0, t = 2 * n + 1, ss = t+1;
                V = ss+1;
                
                for(int i=0; i<V; i++) g[i].clear();
                for(int i=1; i<=n; i++) {
                    scanf("%d", &a[i]);
                    addedge(i, i+n, 1, -1*a[i]);
                }
                for(int i=1; i<=n; i++) {
                    addedge(s, i, 1, 0);
                    addedge(i + n, t, 1, 0);
                    for(int j=i+1; j<=n; j++) {
                        if(a[i] <= a[j] ) {
                            addedge(i+n, j, inf, 0);
                        }
                    }
                }
                addedge(ss, s, k, 0);
                printf("%d\n", -1*solve(ss, t, k));
            }
            return 0;
}
View Code

 

1011 Squrirrel

换根的树形dp

由于有一条边可以删除,所以我们要把儿子分成三种(最长的儿子,次长的儿子,普通儿子),记录最长的儿子,次长的儿子,并预处理出换根时不同类型儿子要的数据,就是同一个父节点下最优的最长路长度。

这个题有一点要清楚,就是对于同一个父节点,只有把最长路儿子的一个路径消成0,才能减少这个父节点的答案。

#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>
// #include<bits/extc++.h>
// using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define fi first
#define se second
#define debug(x) cerr<<#x << " := " << x << endl;
#define bug cerr<<"-----------------------"<<endl;
#define FOR(a, b, c) for(int a = b; a <= c; ++ a)

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
/**********showtime************/

            const int maxn = 2e5+9;
            vector<pii>mp[maxn];
            int f[maxn][2], s[maxn][3];
            int son[maxn][2];
            void dfs1(int u, int fa) {
                f[u][0] =0; f[u][1] = 0;
                s[u][0] =0; s[u][1] = 0;
                s[u][2] = 0;
                int x = 0, y = 0;
                for(pii p : mp[u]) {
                    int v = p.fi;
                    if(v == fa) continue;
                    dfs1(v, u);
                    if(s[u][0] <= f[v][0] + p.se) {
                        y = v;
                        s[u][0] = f[v][0] + p.se;
                        if(s[u][0] > f[u][0]) swap(s[u][0], f[u][0]), swap(x, y);
                    }
                }
                son[u][0] = x;  //最长儿子
                son[u][1] = y;  //次长儿子

                if(y){          //最长儿子用
                    int m = 0;
                    for(pii p : mp[u]) {
                        int v = p.fi;
                        if(v == fa) continue;
                        if(v == x)  continue;
                        if(v != y){
                             m = max(m, f[v][0] + p.se);
                        }
                        else {
                             m = max(m,  min(f[v][1] + p.se, f[v][0]));
                        }
                    }
                    s[u][2] = m;
                }

                if(x) {         //普通儿子用
                    int m = 0;  
                    for(pii p : mp[u]) {
                        int v = p.fi;
                        if(v == fa) continue;
                        if(v != x){
                             m = max(m, f[v][0] + p.se);
                        }
                        else {
                             m = max(m,  min(f[v][1] + p.se, f[v][0]));
                        }
                    }
                    f[u][1] = m;
                }

                if(y) {         //次长儿子用
                    int m = 0;
                    for(pii p : mp[u]) {
                        int v = p.fi;
                        if(v == fa) continue;
                        if(v == y) continue;
                        if(v != x){
                             m = max(m, f[v][0] + p.se);
                        }
                        else m = max(m,  min(f[v][1] + p.se, f[v][0]));
                    }
                    s[u][1] = m;
                }
            }
            int mx, ans;

            void dfs2(int u, int fa, int mx0, int mx1) { 

                int x = max(mx0, f[u][1]);
                
                x = min(x, max(mx1, f[u][0]));


                if(mx > x) mx = x, ans = u;
                else if(mx == x) ans = min(ans, u);

                for(pii p : mp[u]) {
                    int v = p.fi;
                    if(v == fa) continue;
                    
                    int tmpmx0 = mx0;
                    int tmpmx1 = mx1;

                    if(son[u][0] == v) {
                        tmpmx0 = max(mx0, s[u][0]);
                    }
                    else tmpmx0 = max(mx0, f[u][0]);

                    if(son[u][0] == v){
                        tmpmx1 = min(max(mx0, s[u][2]), max(mx1, s[u][0]));//x去掉和去掉次大一条边
                        //注意这里或的关系,只能有一个裁剪
                    }
                    else {
                        if(son[u][1] != v)
                        {
                            tmpmx1 = min(max(mx1, f[u][0]),max(mx0, f[u][1]));
                        }
                        else {
                            tmpmx1 = min(max(mx0, s[u][1]) , max(mx1, f[u][0]));
                        }
                    }

                    tmpmx1 = min(tmpmx0, tmpmx1 + p.se);
                    tmpmx0 += p.se;
                    dfs2(v, u, tmpmx0, tmpmx1);
                }
            }
int main(){
            int T;  scanf("%d", &T);
            while(T--) {
                int n;      
                scanf("%d", &n);
                for(int i=1; i<=n; i++) mp[i].clear();
                for(int i=1; i<n; i++) {
                    int u,v,w;
                    scanf("%d%d%d", &u, &v, &w);
                    mp[u].pb(pii(v, w));
                    mp[v].pb(pii(u, w));
                }
                dfs1(1, 1);
                mx = inf, ans = inf;
                dfs2(1, 1, 0, 0);
                printf("%d %d\n", ans, mx);
            }
            return 0;
}

/*
1
10
2 1 139
3 1 72
4 2 141
5 2 133
6 5 121
7 5 49
8 7 182
9 5 174
10 9 171


output:5 344
*/
View Code

 

posted @ 2019-07-29 18:19  ckxkexing  阅读(262)  评论(0编辑  收藏  举报