HDU 6621 K-th Closest Distance

Time limit 15000 ms

Memory limit 524288 kB

OS Windows

Chinese 题意

To a sequence, Always ask a range, ask all numbers within that range, and the absolute value of the difference p, the new sequence composition, the k-th largest is. In other words, the range in the digital and digital p Always ask to draw the number line, and asked point from the first point p k close to the distance p.

Problem-solving ideas

This digital painting to put on the number line, obviously the weights tree line, but also ask different sub-sections, and that is the Chairman of the tree. Use the Chairman of the tree we can quickly get to the digital case a given interval in the number line.

Observed each of k is small, the maximum 169 (Strange), the time limit 15s, feeling a lot. So the method we use in the game is now ranked number line to find p, p suppose in this section can be routed to the k-name, then we extend to both sides on the number line to find out the name of the k-1 to the left, the first k-2 name of the Ming ...... k-3 has been found on the side or find enough of k, empathy on the right, found at most k digits, then there are at most 2k numbers, also more than three. Them in ascending order from the p to the output of the k-th like. Then pay, then TLE, and then pay the card often, then TLE. End of the game, our problem is the last half-hour red -10 ...... game, because this question many times TLE (like me), Ji card evaluation dozens of pages, played a role in sealing standings (fog).

Positive solution follows - we answer each half, the upper and lower half is \ ([1, sz] \) , sz is the largest number in the sequence. Each query within the size range ([p-mid, p + mid] \) \ number of digits in the range, they reach the distance p is less than equal to \ (MID \) , if more than k, the range to be described smaller, if less than k, explained greater in scale, if equal to k, also shows the range to be narrow, because we have to find the precise range. So-half, to get an answer like this ...... AC requires only 4s.

另外,这题的数字范围也就\(10^6\),用不着离散化。离散化反而增加难度且浪费时间

源代码

那大片注释就是按照比赛过程中那个思路写的不知道啥玩意

#include<stdio.h>
#include<algorithm>

const int N=100010;
int T;
int n,m;
int a[N];
void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int sz;
struct Node{
    int ls,rs;
    int sum;
}t[N*55];
int root[N],cnt=1;
int anss[2000],num;
void update(int &x,int pre,int l,int r,int pos)//pos位置加一
{
    t[x=cnt++]=t[pre];
    t[x].sum++;
    if(l==r) return;
    int mid=l+r>>1;
    if(pos<=mid) update(t[x].ls,t[pre].ls,l,mid,pos);
    else update(t[x].rs,t[pre].rs,mid+1,r,pos);
}

int quek(int srt, int trt, int l, int r, int k)//第k大
{
    if (l == r)
        return l;
    int mid = l + r >> 1;
    int delta = t[t[trt].ls].sum - t[t[srt].ls].sum;
    if (k <= delta)
        return quek(t[srt].ls, t[trt].ls, l, mid, k);
    else
        return quek(t[srt].rs, t[trt].rs, mid + 1, r, k - delta);
}

int quesum(int x,int pre,int l,int r,int ql,int qr)//从1到p的和
{
    if(ql<=l&&r<=qr) return t[x].sum-t[pre].sum;
    int mid=l+r>>1;
    int ans=0;
    if(ql<=mid) ans+=quesum(t[x].ls,t[pre].ls,l,mid,ql,qr);
    if(qr>mid) ans+=quesum(t[x].rs,t[pre].rs,mid+1,r,ql,qr);
    return ans;

}
int main()
{
    //freopen("test.in","r",stdin);
    read(T);
    while (T--)
    {
        int lastans = 0;
        cnt = 1;
        read(n);read(m);
        sz=0;
        for (int i = 1; i <= n; i++)
        {
            read(a[i]);
            sz=std::max(sz,a[i]);
        }
        root[0]=0;t[0]={0,0,0};
        for (int i = 1; i <= n; i++)
        {
            update(root[i], root[i - 1], 1, sz, a[i]);
        }
        for (int i = 1,ll,rr,p,k;i<=m;i++)
        {
            read(ll);
            read(rr);
            read(p);
            read(k);
            //scanf("%d%d%d%d",&ll,&rr,&p,&k);
            ll^=lastans;rr^=lastans;p^=lastans;k^=lastans;
            //printf("%d %d %d %d ************\n",ll,rr,p,k);
           // int p_rk=quesum(root[rr],root[ll-1],1,sz,1,id(p));//问p是区间第几大
            //printf("%d^&\n",p_rk);
            //p_rk向两边扩展,知道扩展了k个,排序,取第k个
            //int left=p_rk,right=p_rk+1;
            /*num=1;
            while(num<=k&&right<=rr-ll+1)
            {
                anss[num++]=std::abs(val[quek(root[ll-1],root[rr],1,sz,right)]-p);
                right++;
            }
            while(num<=(k<<1)&&left>=1)
            {
                anss[num++]=std::abs(val[quek(root[ll-1],root[rr],1,sz,left)]-p);
                left--;
            }
            std::sort(anss+1,anss+num);
            //for(int i=1;i<num;i++) printf("%d ",anss[i]);
            //puts("");
            lastans=anss[k];*/
            int pl = 0, pr = sz;
            //p=p_rk;
            while(pl <= pr) {
                int mid = (pl + pr) >> 1;
                if (quesum(root[rr], root[ll - 1], 1, sz, std::max(1, p - mid), std::min(sz, p + mid) ) >= k)
                {
                    lastans = mid;
                    pr = mid - 1;
                } else pl = mid + 1;
            }
            printf("%d\n",lastans);
        }
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/wawcac-blog/p/11289519.html