2013 Asia Regional Changchun 解題報告

閒來無事,把去年長春的題目都做了下。發現題目都不難,但是有些實現起來確實費勁,很考驗代碼能力。也是我所欠缺的。前途堪憂。

hdu 4813  Hard Code 簽到題,把一個字符串拆爲n個長度爲m的子串。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define INF 0x3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))

using namespace std;

const int maxn = 10100;

char ch[maxn];

int main()
{
    int n, m, T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d%d", &n, &m);
        scanf("%s", ch);
        for(int i = 0; i < n; i ++)
        {
            for(int j = 0; j < m; j ++)
                putchar(ch[i*m+j]);
            putchar('\n');
        }
    }
}
hdu 4814 Golden Radio Base  銀牌題,給一個整數,轉化爲黃金進制數。題目直接把兩個推導給出了,直接利用那兩個式子去鬆弛,把相加完後所有位數鬆弛成1或0就可以了。我是把32位的二進制數先存起來,然後加的,或許要好寫些。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define INF 0x3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))

using namespace std;

const int maxn = 200;

int mid = 100;

int a[40][maxn], b[maxn];

bool check(int c[])
{
    for(int i = 0; i < maxn; i ++)
        if(c[i] > 1) return true;
    return false;
}

bool check2(int c[])
{
    for(int i = 0; i < maxn - 1; i ++)
        if(c[i] && c[i + 1]) return true;
    return false;
}

void gao(int c[])
{
    while(check(c))
    {
        for(int i = maxn - 1; i >= 2; i --)
        {
            int tmp = c[i] / 2;
            c[i] %= 2;
            c[i + 1] += tmp;
            c[i - 2] += tmp;
        }
        for(int i = maxn - 10; i >= 0; i --)
        {
            int tmp = min(c[i], c[i + 1]);
            c[i + 2] += tmp;
            c[i + 1] -= tmp;
            c[i] -= tmp;
        }
    }
    while(check2(c))
    {
        for(int i = maxn - 10; i >= 0; i --)
        {
            int tmp = min(c[i], c[i + 1]);
            c[i + 2] += tmp;
            c[i + 1] -= tmp;
            c[i] -= tmp;
        }
    }
}

void add(int id)
{
    for(int j = 0; j < maxn; j ++)
        b[j] += a[id][j];
    gao(b);
}

int main()
{
    CLR(a, 0);
    a[0][mid] = 1;
    for(int i = 1; i < 33; i ++)
    {
        for(int j = 0; j < maxn; j ++)
            a[i][j] = a[i - 1][j] * 2;
        gao(a[i]);
    }
    int n;
    while(scanf("%d", &n) != EOF)
    {
        CLR(b, 0);
        int cnt = 0;
        while(n)
        {
            if(n & 1) add(cnt);
            cnt ++;
            n >>= 1;
        }
        int l = 0, r = maxn - 1;
        while(b[l] == 0) l ++;
        while(b[r] == 0) r --;
        for(int i = r; i >= mid; i --) printf("%d", b[i]);
        if(l < mid)
        {
            putchar('.');
            for(int i = mid - 1; i >= l; i --) printf("%d", b[i]);
        }
        puts("");
    }
}

hdu 4815 Little Tiger vs. Deep Monkey 簡單題,簡單的dp一下就好了。可以用揹包。把所有能得到的答案求出來,然後直接根據題目給的概率求就可以了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define INF 0x3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))

using namespace std;

const int maxn = 40400;

double dp[maxn];

int main()
{
    int T, n; double p;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d%lf", &n, &p);
        CLR(dp, 0);
        dp[0] = 1;
        int sum = 0;
        for(int i = 1; i <= n; i ++)
        {
            int a; scanf("%d", &a);
            for(int j = sum; j >= 0; j --)
                dp[j + a] += dp[j];
            sum += a;
        }
        if(p == 0) 
        {
            puts("0");
            continue;
        }
        double tot = 0;
        for(int i = 1; i <= sum; i ++)
            tot += dp[i];
        double tmp = 0; int ans;
        for(int i = 1; i <= sum; i ++) if(dp[i])
        {
            tmp += dp[i];
            ans = i;
            if(tmp / tot > p) break;
        }
        printf("%d\n", ans);
    }
}

hdu 4816 Bathysphere 金牌題,讓求一個x範圍是2d的折線的積分,其實就是若干個梯形的面積。然後顯然,我們需要對於每個折線考慮,對於當前情況,要麼是最左邊的折線去掉,右邊折線往右,要麼是把最右邊折線完全覆蓋,左邊折線往右移。這樣的話,顯然兩個折線如果平移到左邊x重合,那麼如果有交點的話顯然就是極值點,所以每次轉移的往右平移折線的時候,順便用極值點更新答案就可以了。就這樣,O(n)就可以求出答案了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define INF 0x3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))

using namespace std;

const int maxn = 200200;

double x[maxn], y[maxn];

struct Point
{
    double x, y;
    Point(double x = 0, double y = 0)
        :x(x), y(y){}
};

inline double call(int i, double xx)
{
    double tmp = y[i] - y[i - 1];
    return (xx - x[i - 1]) / (x[i] - x[i - 1]) * tmp + y[i - 1];
}

inline int sgn(double c)
{
    if(fabs(c) < 1e-8) return 0;
    return c > 0 ? 1 : -1;
}

inline double cross( Point& k, Point& a, Point& b )
{
    return (a.x-k.x)*(b.y-k.y) - (a.y-k.y)*(b.x-k.x);
}
inline double dot( Point& k, Point& a, Point& b )
{
    return (a.x-k.x)*(b.x-k.x) + (a.y-k.y)*(b.y-k.y);
}
inline int segcross( Point a, Point b, Point c, Point d, Point& k )
{
    double s1, s2, s3, s4;
    int d1, d2, d3, d4;
    d1 = sgn(s1 = cross(a, b, c));
    d2 = sgn(s2 = cross(a, b, d));
    d3 = sgn(s3 = cross(c, d, a));
    d4 = sgn(s4 = cross(c, d, b));
    if( (d1^d2) == -2 && (d3^d4) == -2 )
    {
        k = Point( (c.x*s2-d.x*s1)/(s2-s1),(c.y*s2-d.y*s1)/(s2-s1) );
        return 1;
    }
    if( d1 == 0 && sgn(dot(c, a, b)) <= 0 )
    {
        k = c;
        return 2;
    }
    if(    d2 == 0 && sgn(dot(d, a, b)) <= 0 )
    {
        k = d;
        return 2;
    }
    if(    d3 == 0 && sgn(dot(a, c, d)) <= 0 )
    {
        k = a;
        return 2;
    }
    if(    d4 == 0 && sgn(dot(b, c, d)) <= 0 )
    {
        k = b;
        return 2;
    }
    return 0;
}

inline int cmp(double a, double b)
{
    double c = a - b;
    if(fabs(c) < 1e-8) return 0;
    return c > 0 ? 1 : -1;
}

inline double cross(double lx, double ly, int l, double rx, double ry, int r)
{
    Point c;
    int ret = segcross(Point(0, ly), Point(x[l] - lx, y[l]), Point(0, ry), Point(x[r] - rx, y[r]), c);
    if(ret == 0 || ret == 2) return - 1.0;
    return c.x;
}

inline int input()
{
    char ch;
    ch = getchar();
    while(ch < '0' || ch >'9')
    {
        ch = getchar();
    }
    int ret = 0;
    while(ch >= '0' && ch <= '9')
    {
        ret *= 10;
        ret += ch -'0';
        ch = getchar();
    }
    return ret;
}

int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out1.txt", "w", stdout);
    int T, n;
    double L, d;
    scanf("%d", &T);
    while(T --)
    {
        n = input(); L = input();
        for(int i = 1; i <= n; i ++)
            x[i] = input(), y[i] = input();
        d = input();
        double ans = 0, tot = 0;
        double rx, ry, lx = x[1], ly = y[1];
        int l = 2, r;
        for(int i = 2; i <= n; i ++)
        {
            if(cmp(x[i], 2 * d) != 1)
            {
                tot += (y[i] + y[i - 1]) * (x[i] - x[i - 1]);
            }
            else
            {
                rx = d * 2, ry = call(i, rx);
                r = i;
                tot += (ry + y[i - 1]) * (rx - x[i - 1]);
                break;
            }
        }
        ans = tot;
        while(r <= n)
        {
            if(r == l)
            {
                rx = x[l]; ry = y[l];
                lx = x[l] - d * 2; ly = call(l, lx);
                tot = (ry + ly) * (rx - lx);
                r ++;
                ans = max(ans, tot);
                continue;
            }
            double ret = cross(lx, ly, l, rx, ry, r);
            if(sgn(ret + 1.0) != 0)
            {
                double dltx = ret, tmp;
                tmp = (ry + call(r, rx + dltx)) * dltx;
                tot += tmp;
                tmp = (ly + call(l, lx + dltx)) * dltx;
                tot -= tmp;
                lx += dltx; ly = call(l, lx);
                rx += dltx; ry = call(r, rx);
                ans = max(ans, tot);
            }
            if(cmp(x[l] - lx, x[r] - rx) < 0)
            {
                double dltx = (x[l] - lx);
                double tmp = (y[l] + ly) * dltx;
                tot -= tmp;
                tmp = (ry + call(r, rx + dltx)) * dltx;
                tot += tmp;
                lx = x[l]; ly = y[l];
                rx = rx + dltx; ry = call(r, rx);
                l ++;
                ans = max(ans, tot);
            }
            else if(cmp(x[l] - lx, x[r] - rx) > 0)
            {
                double dltx = (x[r] - rx);
                double tmp = (y[r] + ry) * dltx;
                tot += tmp;
                tmp = (ly + call(l, lx + dltx)) * dltx;
                tot -= tmp;
                rx = x[r]; ry = y[r];
                lx = lx + dltx; ly = call(l, lx);
                r ++;
                ans = max(ans, tot);
            }
            else
            {
                double dltx = (x[r] - rx);
                double tmp = (y[r] + ry) * dltx;
                tot += tmp;
                tmp = (ly + call(l, lx + dltx)) * dltx;
                tot -= tmp;
                lx = x[l]; ly = y[l];
                rx = x[r]; ry = y[r];
                l ++; r ++;
                ans = max(ans, tot);
            }
        }
        printf("%.3f\n", ans / (4 * d));
    }
}

hdu 4817 Min-max-multiply 先挖個坑。以後再補。

hdu 4818 RP problem 金牌題。高斯消元。看上去第一眼就是高斯消元,但是如果直接連邊然後每次都消元的話肯定會超時。於是,我們發現其實對於係數矩陣來說,只有最後一行是變化的。再考慮高斯消元的過程,我們可以把前n-1個未知數求解過程對最後一行的影響記錄下來,這樣的話我們只需要對最後一行用當前的記錄內容轉一下就可以了。複雜度O(n^3)。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define INF 0x3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))

using namespace std;

const int maxn = 111;
const double eps = 1e-12;

int sgn(double c)
{
    if(fabs(c) < eps) return 0;
    return c > 0 ? 1 : -1;
}

double a[maxn][maxn], cc[maxn][maxn], cnt[maxn];

int id[maxn];

int gauss(int N, int M, double a[][maxn])
{
    int i, j, r, c, pvt;
    double maxp;
    CLR(cc, 0);
    for(int i = 0; i < N; i ++) id[i] = i;
    for(r = 0, c = 0; r < N && c < M; ++ r, ++ c)
    {
        for(maxp = 0, i = r; i < N; ++ i)
            if(fabs(a[i][c])>fabs(maxp)) maxp = a[pvt=i][c];
        if(sgn(maxp) == 0)
        {
            r--;
            continue;
        }
        if(pvt != r)
            for (j = r; j <= M; ++j) swap(a[r][j], a[pvt][j]);
        if(pvt != r) swap(id[pvt], id[r]);
        cc[id[r]][id[r]] = 1.0;
        for(int i = r + 1; i < N; i ++)
        {
            double tmp = a[i][c] / a[r][c];
            for(int j = c; j <= M; j ++)
            {
                a[i][j] -= tmp * a[r][j];
            }
            for(int k = 0; k < N; k ++)
            {
                cc[id[i]][k] -= tmp * cc[id[r]][k];
            }
        }
    }
    for(i = r; i < N; ++i)
        if (sgn(a[i][M])) return -1;
    if (r < M) return M-r;
    for(i = M-1; i >= 0; --i)
    {
        for (j = i+1; j < M; ++j)
            a[i][M] -= a[j][M]*a[i][j];
        a[i][M] /= a[i][i];
    }
    for(int i = 0; i < N; i ++) cnt[i] = cc[id[N - 1]][i];
    return 0;
}

vector<int> G[maxn];
bool vis[maxn];

bool is[maxn][maxn];

void init(int n)
{
    CLR(a, 0);
    for(int u = 0; u < n; u ++)
    {
        if(!G[u].size()) continue;
        for(int i = 0; i < G[u].size(); i ++)
        {
            int v = G[u][i];
            a[v][u] = 1.0 / G[u].size();
        }
        a[u][u] = -1.0;
    }
    for(int i = 0; i <= n; i ++)
        a[n - 1][i] = 1.0;
}

int main()
{
//    freopen("in.txt", "r", stdin);
    int n, m, T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d%d", &n, &m);
        CLR(is, false);
        for(int i = 0; i < n; i ++)
            G[i].clear(), vis[i] = false;
        while(m --)
        {
            int u, v; scanf("%d%d", &u, &v);
            if(u == v) continue;
            if(is[u][v]) continue;
            is[u][v] = true;
            G[u].push_back(v);
            if(u == n - 1) vis[v] = true;
        }

        init(n);

        int ret = gauss(n, n, a);
        if(ret != 0)
        {
            puts("INF"); continue;
        }

        double p = a[n - 1][n]; int ans = -1;

        for(int i = 0; i < n - 1; i ++) if(!vis[i])
        {
            for(int j = 0; j < n; j ++) a[j][n - 1] = 0.0, a[j][n] = 0.0;
            int sz = G[n - 1].size() + 1;
            a[i][n - 1] = 1.0 / sz;
            for(int j = 0; j < G[n - 1].size(); j ++)
            {
                int v = G[n - 1][j];
                a[v][n - 1] = 1.0 / sz;
            }
            a[n - 1][n - 1] = 1.0;
            a[n - 1][n] = 1.0;
            double tmp = 0, sum = 0.0;
            for(int j = 0; j < n; j ++)
            {
                tmp += cnt[j] * a[j][n - 1];
                sum += cnt[j] * a[j][n];
            }
            tmp = sum / tmp;
            if(sgn(tmp - p) > 0)
            {
                p = tmp; ans = i;
            }
        }
        printf("%d %d\n", 1, ans);
    }
}

hdu 4819 Mosaic 二維線段樹模板題。把大白書那道題敲上去就可以了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define INF 0x3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))

using namespace std;

const int maxn = 4010;

struct SegTree2D
{
    int Max[maxn][maxn], Min[maxn][maxn], n, m;
    int xo, xleaf, x1, y1, x2, y2, x, y, v, vmax, vmin;

    void query1D(int o, int L, int R)
    {
        if(y1 <= L && R <= y2)
        {
            vmax = max(Max[xo][o], vmax);
            vmin = min(Min[xo][o], vmin);
        }
        else
        {
            int M = L + ((R - L) >> 1);
            if(y1 <= M) query1D(o << 1, L, M);
            if(M < y2) query1D(o << 1 | 1, M + 1, R);
        }
    }

    void query2D(int o, int L, int R)
    {
        if(x1 <= L && R <= x2) {xo = o; query1D(1, 1, m); }
        else
        {
            int M = L + ((R - L) >> 1);
            if(x1 <= M) query2D(o << 1, L, M);
            if(M < x2) query2D(o << 1 | 1, M + 1, R);
        }
    }

    void modify1D(int o, int L, int R)
    {
        if(L == R)
        {
            if(xleaf) {Max[xo][o] = Min[xo][o] = v; return ;}
            Max[xo][o] = max(Max[xo << 1][o], Max[xo << 1 | 1][o]);
            Min[xo][o] = min(Min[xo << 1][o], Min[xo << 1 | 1][o]);
        }
        else
        {
            int M = L + ((R - L) >> 1);
            if(y <= M) modify1D(o << 1, L, M);
            else modify1D(o << 1 | 1, M + 1, R);
            Max[xo][o] = max(Max[xo][o << 1], Max[xo][o << 1 | 1]);
            Min[xo][o] = min(Min[xo][o << 1], Min[xo][o << 1 | 1]);
        }
    }

    void modify2D(int o, int L, int R)
    {
        if(L == R) {xo = o; xleaf = 1; modify1D(1, 1, m); }
        else
        {
            int M = L + ((R - L) >> 1);
            if(x <= M) modify2D(o << 1, L, M);
            else modify2D(o << 1 | 1, M + 1, R);
            xo = o; xleaf = 0; modify1D(1, 1, m);
        }
    }

    pair<int, int> query(int x1, int y1, int x2, int y2)///查詢矩陣內最大值和最小值
    {
        this->x1 = x1;
        this->y1 = y1;
        this->x2 = x2;
        this->y2 = y2;
        vmax = -INF; vmin = INF;
        query2D(1, 1, n);
        return make_pair(vmax, vmin);
    }
    void modify(int x, int y, int v)///修改(x, y) 點爲 v
    {
        this->x = x;
        this->y = y;
        this->v = v;
        modify2D(1, 1, n);
    }
} sol;

int input(int &x)
{
    char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    x = 0;
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return x;
}

int main()
{
    int T, cas = 1;
    int n, Q;
    scanf("%d", &T);
    while(T --)
    {
        input(n);
        sol.n = sol.m = n;
        for(int i = 1; i <= n; i ++)
        {
            for(int j = 1; j <= n; j ++)
            {
                int v; input(v);
                sol.modify(i, j, v);
            }
        }
        input(Q);
        printf("Case #%d:\n", cas ++);
        while(Q --)
        {
            int x, y, v;
            input(x); input(y); input(v);
            v /= 2;
            pair<int, int> ret = sol.query(max(1, x - v), max(1, y - v), min(n, x + v), min(n, y + v));
            sol.modify(x, y, (ret.first + ret.second) >> 1);
            printf("%d\n", (ret.first + ret.second) >> 1);
        }
    }
}

hdu 4820 Tower 先挖個坑。

hdu 4821 String,簡單題,直接hash就可以了。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))

using namespace std;

const int maxn = 100100;

map<ULL, int> mp;
char s[maxn];


const int key = 137;
unsigned long long H[maxn], xp[maxn];

void Init_Hash(char *s)///初始化
{
    int n = strlen(s);
    H[n] = 0;
    for(int i = n - 1; i >= 0; i --) H[i] = H[i + 1] * key + (s[i] - 'a');
    xp[0] = 1;
    for(int i = 1; i <= n; i ++) xp[i] = xp[i - 1] * key;
}

unsigned long long Hash(int pos, int len)///初始位置pos,和串長度len
{
    return H[pos] - H[pos + len] * xp[len];
}

int main()
{
    int m, l;
    while(scanf("%d%d", &m, &l) != EOF)
    {
        scanf("%s", s);
        Init_Hash(s);
        int ans = 0, n = strlen(s);
        for(int i = 0; i < l; i ++)
        {
            mp.clear(); int cnt = 0, dif = 0;
            for(int j = i; j + l <= n; j += l)
            {
                ULL val = Hash(j, l);
                mp[val] ++;
                if(mp[val] == 1) dif ++;
                cnt ++;
                if(cnt == m)
                {
                    if(dif == m) ans ++;
                    cnt --;
                    val = Hash(j - m * l + l, l);
                    mp[val] --;
                    if(mp[val] == 0) dif --;
                }
            }
        }
        printf("%d\n", ans);
    }
}


hdu 4822 Tri-war。對於每個詢問,用Lca亂搞一下就可以了。想了半天沒想到好的實現方法,就看了下別人的代碼。然後敲了下。。。sad....

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define LL long long
#define MP make_pair
#define INF 0x3f3f3f3f
#define ULL unsigned long long
#define CLR(a, b) memset(a, b, sizeof(a))

using namespace std;

const int maxn = 100100;

int fa[maxn][20], n, cnt[maxn], dep[maxn];
vector<int> G[maxn];

int dfs(int u, int _fa)
{
    fa[u][0] = _fa; cnt[u] = 1;
    for(int i = 0; i < G[u].size(); i ++)
    {
        int v = G[u][i];
        if(v == _fa) continue;
        dep[v] = dep[u] + 1;
        cnt[u] += dfs(v, u);
    }
    return cnt[u];
}

void Lca_init()
{
//    CLR(fa, -1);
    dep[1] = 0; dfs(1, -1);
    for(int j=1; j<20; j ++)
    {
        for(int i=1; i<=n; i ++)
        {
            if(fa[i][j-1] == -1) fa[i][j] = -1;
            else fa[i][j] = fa[fa[i][j-1]][j-1];
        }
    }
}

int Lca_up(int u, int len)///返回u結點上面len長度的結點。len=1表示返回u的父親
{
    for(int i = 0; i < 20; i ++)
        if(u != -1 && len & (1 << i))
            u = fa[u][i];
    return u;
}

int Lca(int u, int v)///返回u,v的最近公共祖先
{
    if(dep[u] < dep[v]) swap(u, v);
    u = Lca_up(u, dep[u] - dep[v]);
    if(u == v) return u;
    for(int i = 19; i >= 0; i --)
    {
        if(fa[u][i] == fa[v][i]) continue;
        u = fa[u][i];
        v = fa[v][i];
    }
    return fa[u][0];
}

struct Node
{
    int typ, r;
    Node(int typ = 0, int r = 0)
        :typ(typ), r(r) {}
};

Node get_mid(int a, int b)
{
    int fa = Lca(a, b);
    int len = dep[a] + dep[b] - 2 * dep[fa];
    if(dep[a] >= dep[b])
        return Node(1, Lca_up(a, (len - 1) / 2));
    else
        return Node(2, Lca_up(b, len / 2));
}

int query(int a, int b, int c)
{
    Node bn = get_mid(a, b);
    Node cn = get_mid(a, c);
    if(bn.typ == 1 && cn.typ == 1)
    {
        if(dep[bn.r] < dep[cn.r]) swap(bn, cn);
        if(Lca(bn.r, cn.r) == cn.r) return cnt[bn.r];
        else return 0;
    }
    else if(bn.typ == 2 && cn.typ == 2)
    {
        if(dep[bn.r] < dep[cn.r]) swap(bn, cn);
        if(Lca(bn.r, cn.r) == cn.r) return n - cnt[cn.r];
        else return n - cnt[bn.r] - cnt[cn.r];
    }
    else
    {
        if(bn.typ == 2) swap(bn, cn);
        int t = Lca(bn.r, cn.r);
        if(t == cn.r) return n - cnt[cn.r];
        if(t == bn.r) return cnt[bn.r] - cnt[cn.r];
        return cnt[bn.r];
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++)
            G[i].clear();
        for(int i = 1; i < n; i ++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        Lca_init();
        int m;
        scanf("%d", &m);
        while(m --)
        {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            printf("%d %d %d\n", query(a, b, c), query(b, a, c), query(c, a, b));
        }
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章